dipy logo

Site Navigation

NIPY Community

Table Of Contents

Previous topic

Commit message codes

Next topic

Theory and concepts

Keeping code compatible with Pythons 2 and 3

There is useful advice here:

Future imports

For any modules with print statements, and for any modules where you remember, please put:

from __future__ import division, print_function, absolute_import

As the first code line of the file, to use Python 3 behavior by default.

Print

Yeah, you knew that, but use the __future__ import above, and print(something)

Division

Yes, you know, but for Python 3 3/2 return 1.5 not 1. It’s very good to remember to put the __future__ import above at the top of the file to make this default everywhere.

Moved modules

There are compatibility routines in :module:`dipy.utils.six`. You can often get modules that have moved between the versions with (e.g.):

from dipy.utils.six.moves import configparser

See the six.py code and the six.py docs.

Range, xrange

range returns an iterator in Python3, and xrange is therefore redundant, and it has gone. Get xrange for Python 2, range for Python 3 with:

from dipy.utils.six.moves import xrange

Or you might want to stick to range for Python 2 and Python 3, especially for small lists where the memory benefit for xrange is small.

Because range returns an iterator for Python 3, you may need to wrap some calls to range with list(range(N)) to make the code compatible with Python 2 and Python 3.

Reduce

Python 3 removed reduce from the builtin namespace, this import works for both Python 2 and Python 3:

from functools import reduce

Strings

The major difference between Python 2 and Python 3 is the string handling. Strings (str) are always unicode, and so:

my_str = 'A string'

in Python 3 will result in a unicode string. You also need to be much more explicit when opening files; do you want bytes? open(fname, "rb") Or do you want unicode? open(fname, "rt"). In the same way you need to be explicit if you want import io; io.StringIO or io.BytesIO for your file-like objects containing (strings or bytes).

basestring has gone in Python 3. To test whether something is a string, use:

from dipy.utils.six import string_types

isinstance(a_variable, string_types)

Next function

In python 2.6 and higher there is a function next in the builtin namespace, that returns the next result from an iterable thing. In Python 3, meanwhile, the .next() method on generators has gone, replaced by .__next__(). So, prefer next(obj) to obj.next() for generators, and in general when getting the next thing from an iterable.

Except

You can’t get away with except ValueError, err now, because that raises a syntax error for Python 3. Use except ValueError as err instead.

Dictionaries

You’ve lost d.has_key("hello") for dictionaries, use "hello" in d instead.

d.items() returns an iterator. If you need a list, use list(d.items(). d.iteritems() has gone in Python 3 because it is redundant, just use d.items()