Lists, dicts and the Python 2-only APIs

The methods that vanished in Python 3, what they actually did, and the mechanical replacement for each one.

Dictionary methods

Python 2Python 3Note
d.has_key(k)k in dRemoved entirely
d.iteritems()d.items()Python 3 items() is a view, not a list
d.itervalues()d.values()Same change
d.iterkeys()d.keys()Same change
d.items()list(d.items())In 2.7 it already returned a list
d.viewitems()d.items()The 2.7 bridge to 3 semantics
# Python 2
d = {"a": 1, "b": 2}
if d.has_key("a"):
    for k, v in d.iteritems():
        print k, v
keys = d.keys()          # a real list you can sort and mutate
# Python 3 equivalent
d = {"a": 1, "b": 2}
if "a" in d:
    for k, v in d.items():
        print(k, v)
keys = list(d.keys())    # copy if you intend to modify during iteration

The performance reason for iteritems disappeared: in Python 3 items() is already lazy and does not build a list. The one real behaviour change is that mutating a dict while iterating a view raises RuntimeError.

Builtins and sorting

Python 2Python 3
xrange(n)range(n)
range(n)a list in 2; a lazy range object in 3
raw_input()input()
input()evaluated the text as code in 2, removed
cmp(a, b)use (a > b) - (a < b)
reducemoved to functools.reduce
unichr / unicodechr / str
basestringstr
# Python 2: the cmp= sort argument
def by_length(a, b):
    return cmp(len(a), len(b))

names = ["charlie", "bob", "alice"]
names.sort(cmp=by_length)

# Python 3: key functions, or functools.cmp_to_key when you really need a comparator
names = sorted(["charlie", "bob", "alice"], key=len)
from functools import cmp_to_key
names = sorted(["charlie", "bob", "alice"], key=cmp_to_key(by_length))
💡
input() in Python 2 called eval on whatever the user typed, so reading a value was equivalent to executing arbitrary code. Every project that still calls bare input() deserves a review before anything else.

Behaviour changes that surprise people

# 1. sort stability and cmp removal: use key= everywhere
rows = [("a", 2), ("b", 1)]
rows.sort(key=lambda r: r[1])

# 2. dict ordering
# In 2.7 a dict has no guaranteed order. In 3.7+ insertion order is part of the language.
# Do not write code that depends on either, unless you have checked the version.

# 3. map and filter returned lists in 2, iterators in 3
squares = list(map(lambda x: x * x, xrange(5)))

# 4. zip returned a list in 2
pairs = list(zip("abc", xrange(3)))
  • In 2.7, map, filter and zip all return lists, so wrapping them in list() is harmless and makes the intent explicit.
  • Comparison across types was allowed in 2 (so 1 < "a" had an arbitrary but consistent answer) and raises TypeError in 3.
  • dict and set iteration order changed between implementations and, in 3.3, was randomised per process for strings. Never rely on it.

FAQ

Is d.keys() a list or a view in Python 2.7?
A list. The view behaviour arrived in Python 3, and viewkeys() existed in 2.7 as an opt-in preview. Calling list() around it is the portable habit.
How do I replace cmp= without changing behaviour?
Prefer key=, which is faster and clearer. When the comparison genuinely needs two values, wrap the comparator with functools.cmp_to_key so the same logic works under both versions.

The print statement and integer division Migrating to Python 3

Last refreshed 2026-09-18.