What's REALLY New in Python 3
Python 3 brings many, many improvements over Python 2. Those differences which are easy to describe and quickly understand - print being an actual function, integer division, no longer having to type "object" when defining a class - are almost irrelevant compared to the deeper, more profound changes. And that poses a problem: the sheer magnitude and breadth of Python 3's changes makes it hard to get a complete picture.
This page lists and summarizes many of the changes and improvements. Anything backported to Python 2 is deliberately omitted, making it a true diff. If you notice any errors or important omissions, please tell me.
Refreshingly Short Executive Summary
- New syntax and keywords exposing powerful new features; enabling expressive and powerful code patterns; making common idioms and patterns easier to use; and clarifying code that was previously hard to read or reason about.
- An abundance of substantial additions to existing standard library modules, packages, classes, and functions. Too wide-ranging and varied to summarize here. Many of these make a real impact on development speed and productivity... and there are hundreds of them.
A dozen completely new modules in the standard library. These comprehensive, sweeping additions enhance support for network programming, automated testing, concurrency, statistics, debugging, application deployment, and more.
Two whole books could be written detailing everything these new modules enable - the first for the truly epic asyncio module. Volume 2 would just barely contain the others. There's a lot here.
- Reliability improvements that eliminate hidden race conditions, enhance security, remove deterministic but surprising behaviors, and generally make creating robust Python applications much easier.
Again, this summary excludes anything that has been backported to Python 2. (Of course, Python 2 is now frozen except for security fixes, so essentially nothing mentioned in this document is going to be backported in the future.)
Here's some more detail on each of the above points, suffixed with the Python version introducing the change, like this: (3.X)
New Features And Syntax
An incomplete list:
super()
can be called without arguments, simplifying
the common, single-inheritance case. (For me, this alone is worth
upgrading!) (3.0)
Formerly, hasattr()
would catch any exception,
sometimes masking genuine errors. Now, hasattr() has been tightened to
only catch AttributeError and let other exceptions pass through.
(3.2)
Many major changes and improvements to exceptions:
- Implicit and explicit exception chaining, which helps tremendously
with troubleshooting when accidently triggering an exception in an
except:
block, translating one exception type, to another, etc. (PEP 3134 - 3.0) - New raise statement syntax:
raise [expr [from expr]]
(PEP 3109 - 3.0) - Exception objects now store their traceback as the __traceback__
attribute, encapsulating all pertinent information in the exception
object, and often rendering
sys.exc_info()
unnecessary. (PEP 3134 - 3.0) - Additional changes to exceptions as well, but I'll stop here.
Views And iterators instead of lists: Some well-known APIs no longer return lists. For dict, dict.keys(), dict.items() and dict.values() now return views instead of lists (like Python 2's dict.viewitems(), etc.). Consequently, the now-obsolete .iteritems() and .viewitems() (etc.) methods are dropped. map() and filter() return iterators. range() now behaves like xrange() used to behave, except it works with values of arbitrary size. zip() now returns an iterator. All this eliminates large classes of potential memory bottlenecks. (3.0)
Relative and absolute imports (PEP 328 - 3.4)
Coroutines with async and await syntax. Benefits writing asynchronous code; related to the asyncio module. (PEP 492 - 3.5)
New yield from
expression for generator
delegation. Enables new encapsulation patterns for
generators; also used extensively in asyncio. (3.4)
Function argument and return value annotations. This provides a standardized way of annotating a function’s parameters and return value. (PEP 3107 - 3.0)
Everything you thought you knew about binary data and Unicode has changed. Detailed list. (3.0)
Extended Iterable Unpacking - you can now write things like a, b, *rest = some_sequence. (PEP 3132 - 3.0) Also, additional unpacking generalizations (PEP 448 - 3.5).
New metaclass internals and syntax. (PEP 3115 - 3.0)
Keyword-only arguments. Named parameters occurring after *args in the parameter list must be specified using keyword syntax in the call. (PEP 3102 - 3.0)
There is only one built-in integral type, named int; but it behaves mostly like the old long type. Essentially, long renamed to int. (PEP 0237 - 3.0)
PEP 3104: nonlocal statement. Using the new reserved word "nonlocal", you can now assign directly to a variable in an outer (but non-global) scope. Lets you better encapsulate closures where you'd previously have to use a module-global variable, among other things. (3.0)
An expression like 1/2 returns a float. Use 1//2 to get the truncating behavior. The sys.maxint constant was removed, since there is no longer a limit to the value of integers. Octal literals are no longer of the form 0720; use 0o720 instead. (PEP 0238 - 3.0)
The ordering comparison operators (<, <=, >=, >) raise
a TypeError exception when the operands don’t have a meaningful
natural ordering. (The old behavior fell back to the object's
id()
, which was effectively like flipping a coin.) This
automatically eliminates certain kinds of stealthy heisenbugs. (3.0)
memoryview objects now have a release() method, and also now support the context management protocol, allowing timely release of any resources that were acquired when requesting a buffer from the original object. (3.2)
A new warning category, ResourceWarning, has been added. It is emitted when potential issues with resource consumption or cleanup are detected. (3.2)
Python’s import mechanism can now load modules installed in directories with non-ASCII characters in the path name. This solved an aggravating problem with home directories for users with non-ASCII characters in their usernames. (3.2)
New matrix multiplication operator: a @ b. (PEP 465 - 3.5)
Improved Modules
The following modules have substantial improvements in Python 3: abc, aifc, argparse, array, audioop, base64, binascii, bz2, cgi, cmath, code, codecs, collections, colorsys, compileall, contextlib, crypt, curses, datetime, dbm, difflib, dis, distutils, doctest, email, faulthandler, filecmp, ftplib, functools, gc, glob, hashlib, hmac, html, http, idlelib and IDLE, imaplib, imghdr, importlib, inspect, io, ipaddress, itertools, json, logging, math, mmap, multiprocessing, nntplib, operator, os, os.path, pdb, pickle, plistlib, poplib, pprint, pty, pydoc, re, resource, sched, select, shelve, shlex, shutil, signal, smtpd, smtplib, sndhdr, socket, socketserver, sqlite3, ssl, stat, struct, subprocess, sunau, sys, sysconfig, tarfile, tempfile, textwrap, threading, time, tkinter, traceback, types, unicodedata, unittest, urllib, wave, weakref, webbrowser, wsgiref, xml.etree, xml.sax, xmlrpc, zipfile, zlib.
Since almost all modern, nontrivial programs will make extensive
use of the standard library, these improvements collectively yield a
massive impact on how you develop in Python 3. I am compelled to
mention my favorite example: the addition of subtests in the
unittest
module has changed the way I write my tests. Note
this is just one out of over two hundred distinct improvements.
I had started to write out a summary of what those changes are for each module, but quickly realized it would take me several full days just to compose a first draft. Unfortunately, the only way I know to get a good sense of which are most valuable to you is to develop in Python 3 for a while; get used to what's there; and then experience the pain of missing them when you go back to Python 2.
New Standard Library Modules
asyncio: New API for asynchronous IO (PEP 3156 - 3.4)
unittest.mock (replace parts of your system under test with mock objects) (3.3)
enum: Support for enumeration types (PEP 435 - 3.4)
statistics: A basic numerically stable statistics library (PEP 450 - 3.4)
venv (Python virtual environments, now built into the standard distribution) (3.3)
The concurrent.futures module (PEP 3148 - 3.2)
pathlib: Object-oriented filesystem paths (PEP 428 - 3.4)
selectors: High-level and efficient I/O multiplexing, built upon the select module primitives (part of PEP 3156 - 3.4)
ipaddress (high-level objects representing IP addresses and masks) (3.3)
lzma (compress data using the XZ / LZMA algorithm) (3.3)
faulthandler (helps debugging low-level crashes) (3.3)
tracemalloc: Trace Python memory allocations (PEP 454 - 3.4)
Conclusion
The changes listed here make a qualitative difference in how you develop Python applications. To capture it in a nutshell, Python 3 makes it easier to develop high quality software, compared to Python 2.
There are still legitimate reasons to choose 2.7 (or even earlier) for certain projects. Increasingly often, though, Python 3 is a reasonable choice; all that's in the way is unfamiliarity and inertia. Where appropriate, I encourage you to try the newer version for your next small project. You might like it a lot.
References
Thorough list of features and improvements released in each Python 3 version to-date:
- What's New in Python 3.0
- What's New in Python 3.1
- What's New in Python 3.2
- What's New in Python 3.3
- What's New in Python 3.4
- What's New in Python 3.5
Resources listing some of those 3.x improvements backported to 2.x:
In writing this, I have also relied on my experience developing Python for nearly ten years (and in particular, writing more code in Python 3 than Python 2 in the last three years). This recent interview dives into that background if you are curious.