A programmer may try to get you to install Python 3 and learn that. Say, "When all of the Python code on your computer is Python 3, then I'll try to learn it." That should keep them busy for about 10 years.

- Zed Shaw, Learn Python The Hard Way

Yesterday, I started a tiny project that allows you to see the utilization of EWS labs at the University of Illinois. One of my goals for this project was to learn to write Python better. I treat Python as my scripting language; I know what it capable of many, many things, but I don't always know the fastest or best (or most Pythonic) way to accomplish those things. For instance, list comprehensions are something that I consistently need to look up. One thing that I haven't dabbled with at all, however, is writing code in Python 3. The reason I avoided it is because way back when I decided to Learn Python the Hard Way, I read that quote by Zed Shaw, installed Python 2, and never looked back (or forward, as it were).

What's Source Compatible Python?

Source compatible Python refers to code that runs the same way using either the Python 2 or Python 3 interpreter. Doing this is a way that many projects have found is the easiest way to start supporting Python 3. I used this my EWS utilization script as an opportunity to start writing this kind of code, and I learned some tips and tricks for the best ways to do this.

Future Imports

from __future__ import print_function  
from __future__ import division  

Two easy and important changes to make is to import behavior from Python 3 into Python 2, and then write the code as if it was Python 3. from __future__ import print_function changes the print statement into a function print() that works almost exactly like the statement. This is the biggest pitfall for Python 2 programmers coming to Python 3.

Arguably the biggest pitfall for new programmers to Python 2 is this:

>>> 1/2

Python 3 changes (corrects?) this behavior by casting these ints to floats automatically, so precision is always increased. This behavior for the / operator can be imported into Python 2 with from __future__ import division.

It's worth noting that __future__ imports must be the first statements in a script (i.e. they can't come after other imports). See below for one more __future__ import regarding Unicode string literals.

Try-Catch Imports

#! /usr/bin/env python

    # For Python 3.0 and later
    from urllib.request import urlopen
except ImportError:  
    # Fall back to Python 2's urllib2
    from urllib2 import urlopen

html = urlopen("http://www.google.com/")  

from StackOverflow

Many libraries had their structures change in Python 3. For my project, I had to deal with urllib. One way to deal with differences is as above: import the same function or object from modules. Try for Python 3 support, then fall back to Python 2 support.

Unicode Strings

In Python 3, all strings are Unicode. You must take care with how you handle strings; Python 2 allowed text strings and byte strings to be used almost interchangeably, and Python 3 does not. Usually, this sort of thing can be taken care of by deciding to only use Unicode literals by using from __future__ import unicode_literals, and using decode to get byte strings from other encodings when necessary.

It's Not Easy

There are many more stumbling blocks when writing source compatible Python. These are just some of a few that I've encountered. Please let me know if you think there's some that I should include here.