Python 2 has a limited lifetime, and by 2020, there will no longer be any active development on Python 2.
http://legacy.python.org/dev/peps/pep-0373/
Why? Apparently it was easier to make a shiny new python by breaking backwards compatibility. The good news is it's relatively painless to switch small projects over to Python 3, and most major Python packages already support Python 3 (including most of the scientific stack: numpy, scipy, pandas, astropy).
In [1]:
import sys
print(sys.version)
print
is now a function, no longer a keywordexec
is now a function, no longer a keyword/
, no longer truncates! (no more 2/3 == 0)range()
, zip()
, map()
, filter()
, dict.keys()
, dict.items()
, dict.values()
, all return an iterator instead of a list'a' < 1
will fail with an errorurllib
is reorganizedFor a more complete list, see
http://ptgmedia.pearsoncmg.com/imprint_downloads/informit/promotions/python/python2python3.pdf
In [7]:
# python2 has list comprehensions
[x ** 2 for x in range(5)]
Out[7]:
In [8]:
# python3 has dict comprehensions!
{str(x): x ** 2 for x in range(5)}
Out[8]:
In [9]:
# and set comprehensions
{x ** 2 for x in range(5)}
Out[9]:
In [10]:
# magic dictionary concatenation
some_kwargs = {'do': 'this',
'not': 'that'}
other_kwargs = {'use': 'something',
'when': 'sometime'}
{**some_kwargs, **other_kwargs}
Out[10]:
In [11]:
# unpacking magic
a, *stuff, b = range(5)
print(a)
print(stuff)
print(b)
In [2]:
# native support for unicode
s = 'Το Ζεν του Πύθωνα'
print(s)
In [12]:
# unicode variable names!
import numpy as np
π = np.pi
np.cos(2 * π)
Out[12]:
In [13]:
# infix matrix multiplication
A = np.random.choice(list(range(-9, 10)), size=(3, 3))
B = np.random.choice(list(range(-9, 10)), size=(3, 3))
print("A = \n", A)
print("B = \n", B)
print("A B = \n", A @ B)
print("A B = \n", np.dot(A, B))
The old string formatting (with %
) is depricated in favor of str.format()
. A good comparison of the two can be found here:
Dealing with unicode can be a pain when *nix doesn't give or expect unicode. Sometimes importing data in python3 will give you strings with a weird b
in front. These are bytestrings, and they can usually be converted to unicode strings with bytestring.decode('utf-8')
.
In [14]:
s = 'asdf'
b = s.encode('utf-8')
b
Out[14]:
In [15]:
b.decode('utf-8')
Out[15]:
In [16]:
# this will be problematic if other encodings are used...
s = 'asdf'
b = s.encode('utf-32')
b
Out[16]:
In [17]:
b.decode('utf-8')
Ever wonder what those from __future__ import foo
statements were doing?
http://python-future.org/quickstart.html
Using the future
package, you can write code that works for either Python 2 or Python 3. You'll still have to avoid using some Python 3 specific syntax.
In [18]:
# shouldn't change anything in python3
from __future__ import print_function, division
print('non-truncated division in a print function: 2/3 =', 2/3)
2to3
will convert Python 2 code to Python 3. It may come with your python installation, or you may have to install it separately (in the Fedora package repository it is found under python-tools
).
Simply run 2to3 myscript.py
to see the diff of changes, then run 2to3 -w myscript.py
to write the changes. The old file is saved as myscript.py.bak
. You can also run it on an entire directory to convert a whole package.
Note that there are some edge cases to deal with. For instance, it can't tell where you wanted truncated division vs normal division. Also it leaves old style formatting (though this should still work).
To convert Jupyter notebooks, you can install the jupytercontrib
package (via pip as pip install jupytercontrib
), then run
jupyter nbconvert --to 2to3 mynotebook.ipynb
It will create a new notebook called mynotebook.nbconvert.ipynb
which will have relevent cells converted to python3 syntax and have the default kernel set to python3.