Overview
Teaching: 20 min Exercises: 0 minQuestions
What are some good resources for transitioning to Python 3?
Objectives
Learn about the new Python.
About ten years ago, Guido Van Rossum, the Python author and Benevolent Dictator for Life (BDFL), along with the Python community, decided to make several concurrent backward incompatible changes to Python 2.5 and release a new version, Python 3.0. The main changes were:
input
removed, and raw_input
now renamed to input
exec
/
float division and //
truncating division__prepare__
nonlocal
variablesfirst, *rest = makes_a_tuple()
.pyc
files, instead using __pycache__
directoriesint
and long
types into one unlimited length integer typeUnfortunately, this list was comprehensive enough to break virtually every python script ever written. So, to ease the transition, 3.0 and 2.6 were released simultaneously, with the other, backward compatible new features of 3.0 being also included in 2.6. This happened again with the releases of 3.1 and 2.7. Not wanting to maintain two Pythons, the BDFL declared that 2.7 was the last Python 2 series release.
Side note about speed
These changes (mostly the unicode one) also made Python much slower in version 3.0. Since then, however, there have been many speed and memory improvements. Combined with new C extensions for some modules, Python 3 is now usually as fast or faster than Python 2.
The original, officially sanctioned upgrade path was one of the biggest issues with moving to Python 3. A script, 2to3
, was supposed to convert code to Python 3, and then the old version could be eventually dropped. This script required a lot of manual intervention (things like the unicode strings require knowledge of the programmer’s intent), and required library authors to maintain two separate versions of the code. This hindered initial adoption with many major libraries unwilling to support two versions for
Python 3 support.
Unofficial authors tried making a new script, 3to2
, which worked significantly better, but still was hindered by the dual copies of code issue.
Another decision also may have slowed adoption. Part way through the development of Python 3.2 up to 3.4, the decision was made to avoid adding any new features, to give authors time to adopt code to a stable Python 3. This statement could be taken in reverse; why update to Python 3 when it does not have any new features to improve your program? The original changes (as listed above) were not enough to cause mass adoption.
This dreary time in Python development is now drawing to a close, thanks to a change in the way authors started approaching Python compatibility. There is such a good overlap between Python 2.6 or Python 2.7 and Python 3.3+ that a single code base can support them both. The reason for this is the following three things:
__future__
These were capitalized by the unofficial library authors, and now almost every library is available as a single code base for Python 2 and 3. Most of the new standard libraries, and even a few language features, are regularly backported to Python 2, as well.
The original compatibility library, six (so named because 2 times 3 is 6), provides tools to make writing 2 and 3 compatible code easy. You just import six, and then access the renamed standard libraries from six.moves
. There are wrappers for the changed features, such as six.with_metaclass
.
These features are not hard to wrap yourself, so many libraries implement their own six
wrapper to reduce dependencies and overhead.
This is a newer library with a unique approach. Instead of forcing a usage of a special wrapper, the idea of future is to simply allow code to be written in Python 3, but work in Python 3. For example, from builtins import input
will do nothing on Python 3 (builtins
is where input
lives), but on Python 2 with future
installed, builtins
is part of future
and will import the future
version. You can even patch in the Python 3 standard library names
with a standard_library.install_aliases()
function.
Future also comes with it’s own version of the conversion scripts, called futurize
and pasteurize
, which use the future library to make code that runs on one version run on both versions. An alpha feature, the autotranslate
function, can turn a library that supports only Python 2 into a Python 3 version on import.
Several of the new libraries and features have been backported to Python 2. I’m not including ones that were backported in an official Python release, like argparse
.
pathlib
: A simple, object oriented path library from Python 3.4enum
: A python package for enumerations from Python 3.4mock
: A version of unittest.mock
from Python 3.3futures
: This is the concurrent.futures
package in Python 3.2statistics
: From Python 3.4selectors34
: The selectors
package from Python 3.4typing
: Type hints from Python 3.5trollius
: The asyncio
package, with a new syntax for yield from
, from Python 3.4configparser
, subprocess32
, functools32
, and the various backports
-dot-something packages.These are features that have been released in a version of Python after 3.0 that are not in the older Python 2 series:
@
(3.5)async
and await
syntax for asynchronous operations (3.5)*
and **
operators work in more places like you’d expect (3.5)yield from
, finally allows safe factorisation of generators (3.3)The Python 3 series is still evolving, with more features planned for the upcoming 3.6 release. A few of them are:
Finally! You can write code such as the following now:
x = 2
print(f"The value of x is {x}")
This is indicated by the f
prefix, and can take almost any valid python expression. It does not have the scope issues that the old workaround, .format(**locals())
encounters.
This will be great for type hints, IDE’s, and Cython, but the syntax is a little odd for Python. It’s based on function annotations. A quick example:
an_empty_list_of_ints: List[int] = []
will_be_a_str_later: str
This stores the variable name and the annotation in an __annotations__
dictionary for the module or the class that they are in.
Python dictionaries are now partially ordered; due to huge speedups in the C definition of ordered dicts, the dict
class is now guarantied to iterate in order as long as nothing has been changed since the dict
creation. This may sound restrictive, but it enables many features; you can now discover the order keyword arguments were passed, the order class members were added, and the order of {}
dicts. If you want to continue to keep or control the order, you should move the dict
to an
OrderedDict
, as before. This makes ordered dictionaries much easier to create, too.
Warning
Only class member order and keyword argument order are ensured by the language; the ordering of
{}
is an implementation detail. This detail works in both CPython 3.6 and all versions PyPy, however. This may become language mandated in the future.
1_000_000
.__init_subclass__
class method.__set_name__
.__fspath__()
, allows any object to indicate that it represents a path. Finally pathlib works without wrapping it in a str()
!async
list comprehensions, and async
generators.secrets
module for password related randomization functions.The current status of the python releases is as follows:
u""
was added back in as a no-op. Note that PyPy3 is currently based on Python 3.3.5.Further reading:
Key Points
Work with Python.