What's REALLY New in Python 3

A lot more than you might realize.

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

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:

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)


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.


Thorough list of features and improvements released in each Python 3 version to-date:

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.