Search
Python 2 vs. Python 3

Python 2 versus 3

Henry Schreiner

Disclaimer: This notebook is going to focus on reasons to use Python 3 more than on the details of porting code. See https://lhcb.github.io/developkit-lessons/first-development-steps/06b-python.html for a more complete description and help porting.

Unicode

This is the most impactful, biggest change. All strings now default to Unicode instead of bytes. Supporting both unicode and bytes was originally a library challenge, but has mostly been solved.

  • Enables unicode in more places, better supported
  • No longer dual builds of Python (wide vs. narrow)
  • Encoding/decoding often more explicit
  • Can use in Python 2 with from __future__ import unicode_literals (careful!)

</font>

  • Was originally much slower/more memory
  • Encoding/decoding often more explicit

</font>

Python 3 changed print to a function. This means even the "Hello World" program changed!

  • Can use print as a function/method name
  • Easier redirection, ending, separator, flush
  • Can replace print if needed
  • Can use in Python 2 with from __future__ import print_function

</font>

  • Have to type two more chars for every print
  • Lost "soft space" feature

</font>

%%python2
print "Hello world!"
Hello world!
print("Hello world!")
Hello world!

Division

This is the other big change for users, but was so popular, almost everyone adds from __future__ import division!

  • Division of integers with / now produces floats if needed.
  • Truncating division with // supported in Python 2 and 3.
%%python2
print 1/2
0
print(1 / 2)
0.5

Removals

Python 3 removes several things that were either deprecated or in need of replacement.

  • Classic style classes
  • Tuple unpacking in function arguments (rarely used, replaced by new features)
  • Backticks for repr (will not be used again)
  • Comma syntax for exceptions (replaced by as a long time ago)
  • Removed input, renamed raw_input to input

Smaller changes

  • Import now looks for system packages first (from __future__ import absolute_import)
  • exec is a function now
  • Metaclasses have a new syntax, more options for overriding class construction
  • nonlocal variables added
  • Extended tuple unpacking first, *rest = iterable
  • Unified int and long
  • Added function annotations (and variable annotations in 3.6)

Other nice changes

  • Better tracebacks
  • Better segfault reporting
  • Better REPL (tab completion, for example) *

New standard libraries (with backports)

  • pathlib (pathlib2)
  • enum (enum)
  • unittest.mock (mock)
  • concurrent.futures (futures)
  • statistics (statistics)
  • selectors (selectors34)
  • typing (typing)
  • asyncio (trollius)
  • dataclass 3.7
  • importlib.resources (importlib_resources) 3.7

New features

  • async and await (3.5, 3.7)
  • Better unpacking (3.5)
  • Function signature objects (3.3)
  • Lots of Windows and Windows launcher improvements
  • yield from (3.3)
  • Added breakpoint() function (3.7)

New syntax: Matrix multiplication operator (3.5)

A matrix multiplication operator was added: @ (mATrix). Not used in the standard library; provided for libraries like Numpy.

Before:

S = np.dot((np.dot(H, beta) - r).T,
           np.dot(inv(np.dot(np.dot(H, V), H.T)), np.dot(H, beta) - r))

After:

S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)

New syntax: Formatted string literals (3.6)

Adding an f to the front of a string allows most valid Python to be interpolated inside {}s.

print(f"1 + 2 = {1+2}")
1 + 2 = 3

Ordered dictionaries (3.6)

Dictionaries in CPython since 3.6 (official language specification in 3.7) are now faster and ordered! This affects normal dictionaries, keyword arguments, and class ordering.

a = {"b": None, "a": None, "c": None}
print(list(a))
['b', 'a', 'c']
%%python2
a = {'b': None, 'a': None, 'c': None}
print(list(a))
['a', 'c', 'b']