This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.
Python 2 and 3 are very similar, but there are some basic differences
that make a program written in one version incompatible with the
other version. The most important differences are that 1/10
is interpreted as float division (equal 0.1
) in Python 3, while
Python 2 interprets the expression as integer division (which equals 0
).
The raw_input
function in Python 2 is named input
in Python 3, while
the input
function in Python 2 (meaning eval
applied to raw_input
)
does not exist in Python 3. The major difference, though, is the
print statement in Python 2, which must be a call to the
print
function in Python 3. Some more differences related to
constructions in this document appear below.
xrange
in Python 2 is range
in Python 3
The range
function in Python 2 generates a list of integers, and for
very long loops this list may consume significant computer memory.
The xrange
function in Python was therefore made to just generate
a series of integers without storing them. In Python 3, range
is
the xrange
function from Python 2. If one wants a list of
integers in Python 3, one has to do list(range(5))
to store the
output from range
in a list.
The Python 3 idea of letting range
just generate one object at a time
instead of storing all of them applies to many other constructions too.
Let d
be a dictionary. In Python 2, d.keys()
returns a list of
the keys in the dictionary, while in Python 3, d.keys()
just enables
iteration over the keys in a for loop.
Similarly, d.values()
and d.items()
returns lists of values or
key-value pairs in Python 2, while in Python 3 we can only iterate over
the values in a for loop. A simple loop like
for key in d.keys():
...
works well for both Python versions, but
keys = d.keys()
in Python 2, where we want the keys as a list, needs a modification in Python 3:
keys = list(d.keys())
We should add that for key in d.keys()
is not the preferred syntax anyway - use for key in d
. Also, if we just want a for loop over all key-value pairs,
we can use d.iteritems()
which does not return any list, neither in Python 2
nor in Python 3.
We have used the urllib
module in
the sections How to access web pages in programs and Example: Reading pure text files.
Python 3 has some different names for this module:
# Python 2
import urllib
with urllib.urlopen('http://google.com') as webfile:
text = webfile.read()
urllib.urlretrieve('http://google.com', filename='tmp.html')
# Python 3
import urllib.request as urllibr
with urllibr.urlopen('http://google.com') as webfile:
text = webfile.read()
urllibr.urlretrieve('http://google.com', filename='tmp.html')
A lot of other modules have also changed names, but the futurize
program (see below) help you to find the right new names.
A standard Python 2 string, s = 'abc'
, is a sequence of bytes, called
byte string in Python 3, declared as s = b'abc'
in Python 3. The assignment
s = 'abc'
in Python 3 leads to a unicode string and is equivalent to
s = u'abc'
in Python 2. To convert a byte string in Python 3 to
an ordinary (unicode) string, do s.decode('utf-8')
.
String handling is often the most tricky task when converting Python 2
code to Python 3.
If you work with Python packages, relative imports inside a package has slightly different
syntax in Python 2 and 3.
Say you want to import somefunc
from a module somemod
in some
other module at the same level (same subfolder) in the package.
Python 2 syntax would be from somemod import somefunc
, while Python 3
demands from .somemod import somefunc
. The leading dot in the
module name indicates that
somemod
is a module located in the same subfolder as the file containing
this import statement. The alternative import, import somemod
,
in Python 2 must read from . import somemod
in Python 3.
One
can use the futurize
program to turn a Python 2 program into a version that
works with both Python 2 and 3. The recommended command for turning a
program or module prog.py
of arbitrary complexity common Python 2/3
version is
Terminal> futurize --all-imports -w -n -o py23 prog.py
The file py23/prog.py
will usually run under Python 2 and 3, but sometimes
manual adjustments are needed.
By frequently running just futurize prog.py
to see what needs to be
changed, you can learn a lot of the differences between Python 2 and 3
and also change your programming style in Python 2 so that it comes
even closer to Python 3. The python-future
documentation has
a very useful list of difference between Python 2 and 3 and recipes on
how to make common code for both versions.
Porting of larger programs from Python 2 to 3 is recommended to use
futurize
in a two-stage fashion.