Part of my work in different companies has been about the transition fromp python2 to python3. It used to be recommended to use 2to3, but nowadays most of the efforts are around the use of __future__ as well as the future and six library

print

This is the most obvious point of conflict. The old print “string” doesn’t work anymore. Any program that uses print will suffer from this error immediately and not continue.

print "abc"

vs

print(abc)

New modules and classes names

A few of the libraries that come with python have changed their name to something else That affects to the oneliners too, like the http server.

  • urllib
  • StringIO
  • mock

Low level is handled for you in py3

In python2 the choice between a high level python library and a low level c version of it is at import time.

Example:

    import profile
    import cProfile

In python3 the interpreter decides which version to use for you

String becomes unicode and bytes

In python2 there are two classes to handle string:

  • str
  • unicode

They can convert to each other with .decode(), .encode() or casting to unicode() and str(). Internally py2 uses str unless otherwise specified, and the handling of low level bytes and actual strings is mixed up. To make things worse, calling encode for a str creates another str.

In python3 these classes have been changed to:

  • bytes
  • str

default behavior

In python2, all strings are bytes by default, and only u'' strings are unicode. In order to change this, from __future__ import unicode_literals converts all the literal strings to unicode. Because the default in py2 is to have the ascii byte representation This might break some stuff.

Workflow changes

most libraries use .decode() and .encode() to alter the meaning of a string. In python 3 strings are always encoded, and bytes are always decoded.

Absolute imports as default

from __future__ import absolute_import makes python2 behave like python3.

Division

py2 division works like integer division when both parts are integers. Py3 returns a float. from __future__ import division makes python2 behave like python3

Round

py2 division when rounding middle values (0.5) rounds to the further away from 0 value. round(0.5) will return 1.0. Python3 returns the banker division, returning the nearest to the even number. round(0.5) returns 0. It also fixes the odd behavior of returning float in all cases.

numpy and native ints and floats

Numpy int64 and other types no longer inherit from int. This means that any json serialization of these types will fail

Dictionary order has changed

The dictionary order is always the same in python2, as there is no hash randomization. For python <= 3.4 the order wasn’t guaranteed at all. from python 3.5 onwards the implementation changed and order was guaranteed to be the insertion order

Everything is views or defered

dictionary.items(), dictionary.values(), etc.. are now views, which means they don’t generate a copy of the content. Things like map, reduce, filter no longer return a list either.

The effect of this change is that things like dict.items()[0] or json.dumps(map(...)) no longer works

Performance is mostly worse