diff --git a/porting-code-to-python-3-with-2to3.html b/porting-code-to-python-3-with-2to3.html index d979d71..fb1cdcf 100644 --- a/porting-code-to-python-3-with-2to3.html +++ b/porting-code-to-python-3-with-2to3.html @@ -32,25 +32,25 @@ td pre{padding:0;border:0}
In Python 2, print was a statement. Whatever you wanted to print simply followed the print keyword. In Python 3, print() is a function — whatever you want to print is passed to print() like any other function.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -print |
-print() |
| ② | -print 1 |
-print(1) |
| ③ | -print 1, 2 |
-print(1, 2) |
| ④ | -print 1, 2, |
-print(1, 2, end=' ') |
| ⑤ | -print >>sys.stderr, 1, 2, 3 |
-print(1, 2, 3, file=sys.stderr) | Notes + | Python 2 + | Python 3 + + |
| ① + | print
+ | print()
+ |
| ② + | print 1
+ | print(1)
+ |
| ③ + | print 1, 2
+ | print(1, 2)
+ |
| ④ + | print 1, 2,
+ | print(1, 2, end=' ')
+ |
| ⑤ + | print >>sys.stderr, 1, 2, 3
+ | print(1, 2, 3, file=sys.stderr)
|
print() without any arguments.
@@ -62,16 +62,16 @@ td pre{padding:0;border:0}
Python 2 had two string types: Unicode strings and non-Unicode strings. Python 3 has one string type: Unicode strings.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -u"PapayaWhip" |
-"PapayaWhip" |
| ② | -ur"PapayaWhip\foo" |
-r"PapayaWhip\foo" |
| Notes + | Python 2 + | Python 3 + + |
| ① + | u"PapayaWhip"
+ | "PapayaWhip"
+ |
| ② + | ur"PapayaWhip\foo"
+ | r"PapayaWhip\foo"
|
unicode() global functionPython 2 had two global functions to coerce objects into strings: unicode() to coerce them into Unicode strings, and str() to coerce them into non-Unicode strings. Python 3 has only one string type, Unicode strings, so the str() function is all you need. (The unicode() function no longer exists.)
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| - | unicode(anything) |
-str(anything) |
| Notes + | Python 2 + | Python 3 + + |
| + | unicode(anything)
+ | str(anything)
|
long data typePython 2 had separate int and long types for non-floating-point numbers. An int could not be any larger than sys.maxint, which varied by platform. Longs were defined by appending an L to the end of the number, and they could be, well, longer than ints. In Python 3, there is only one integer type, called int, which mostly behaves like the long type in Python 2. Since there are no longer two types, there is no need for special syntax to distinguish them.
Further reading: PEP 237: Unifying Long Integers and Integers.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -x = 1000000000000L |
-x = 1000000000000 |
| ② | -x = 0xFFFFFFFFFFFFL |
-x = 0xFFFFFFFFFFFF |
| ③ | -long(x) |
-int(x) |
| ④ | -type(x) is long |
-type(x) is int |
| ⑤ | -isinstance(x, long) |
-isinstance(x, int) |
| Notes + | Python 2 + | Python 3 + + |
| ① + | x = 1000000000000L
+ | x = 1000000000000
+ |
| ② + | x = 0xFFFFFFFFFFFFL
+ | x = 0xFFFFFFFFFFFF
+ |
| ③ + | long(x)
+ | int(x)
+ |
| ④ + | type(x) is long
+ | type(x) is int
+ |
| ⑤ + | isinstance(x, long)
+ | isinstance(x, int)
|
Python 2 supported <> as a synonym for !=, the not-equals comparison operator. Python 3 supports the != operator, but not <>.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -if x <> y: |
-if x != y: |
| ② | -if x <> y <> z: |
-if x != y != z: |
| Notes + | Python 2 + | Python 3 + + |
| ① + | if x <> y:
+ | if x != y:
+ |
| ② + | if x <> y <> z:
+ | if x != y != z:
|
has_key() dictionary methodIn Python 2, dictionaries had a has_key() method to test whether the dictionary had a certain key. In Python 3, this method no longer exists. Instead, you need to use the in operator.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -a_dictionary.has_key("PapayaWhip") |
-"PapayaWhip" in a_dictionary |
| Notes + | Python 2 + | Python 3 + + |
| ① + | a_dictionary.has_key("PapayaWhip")
+ | "PapayaWhip" in a_dictionary
|
| ② | -a_dictionary.has_key(x) or a_dictionary.has_key(y) |
-x in a_dictionary or y in a_dictionary |
| ③ | -a_dictionary.has_key(x or y) |
-(x or y) in a_dictionary |
| ④ | -a_dictionary.has_key(x + y) |
-(x + y) in a_dictionary |
| ⑤ | -x + a_dictionary.has_key(y) |
-x + (y in a_dictionary) | a_dictionary.has_key(x) or a_dictionary.has_key(y)
+ | x in a_dictionary or y in a_dictionary
+ |
| ③ + | a_dictionary.has_key(x or y)
+ | (x or y) in a_dictionary
+ |
| ④ + | a_dictionary.has_key(x + y)
+ | (x + y) in a_dictionary
+ |
| ⑤ + | x + a_dictionary.has_key(y)
+ | x + (y in a_dictionary)
|
In Python 2, many dictionary methods returned lists. The most frequently used methods were keys(), items(), and values(). In Python 3, all of these methods return dynamic views. In some contexts, this is not a problem. If the method's return value is immediately passed to another function that iterates through the entire sequence, it makes no difference whether the actual type is a list or a view. In other contexts, it matters a great deal. If you were expecting a complete list with individually addressable elements, your code will choke, because views do not support indexing.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -a_dictionary.keys() |
-list(a_dictionary.keys()) |
| ② | -a_dictionary.items() |
-list(a_dictionary.items()) |
| ③ | -a_dictionary.iterkeys() |
-iter(a_dictionary.keys()) |
| ④ | -[i for i in a_dictionary.iterkeys()] |
-[i for i in a_dictionary.keys()] |
| ⑤ | -min(a_dictionary.keys()) |
-no change |
| Notes + | Python 2 + | Python 3 + + |
| ① + | a_dictionary.keys()
+ | list(a_dictionary.keys())
+ |
| ② + | a_dictionary.items()
+ | list(a_dictionary.items())
+ |
| ③ + | a_dictionary.iterkeys()
+ | iter(a_dictionary.keys())
+ |
| ④ + | [i for i in a_dictionary.iterkeys()]
+ | [i for i in a_dictionary.keys()]
+ |
| ⑤ + | min(a_dictionary.keys())
+ | no change |
2to3 errs on the side of safety, converting the return value from keys() to a static list with the list() function. This will always work, but it will be less efficient than using a view. You should examine the converted code to see if a list is absolutely necessary, or if a view would do.
@@ -202,24 +202,24 @@ td pre{padding:0;border:0}
httpIn Python 3, several related HTTP modules have been combined into a single package, http.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -import httplib |
-import http.client |
| ② | -import Cookie |
-import http.cookies |
| ③ | -import cookielib |
-import http.cookiejar |
| ④ | +||
| Notes + | Python 2 + | Python 3 + + |
| ① + | import httplib
+ | import http.client
+ |
| ② + | import Cookie
+ | import http.cookies
+ |
| ③ + | import cookielib
+ | import http.cookiejar
+ |
| ④ | |
-import http.server | import http.server
|
http.client module implements a low-level library that can request HTTP resources and interpret HTTP responses.
@@ -230,32 +230,32 @@ import CGIHttpServer
urllibPython 2 had a rat's nest of overlapping modules to parse, encode, and fetch URLs. In Python 3, these have all been refactored and combined in a single package, urllib.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -import urllib |
-import urllib.request, urllib.parse, urllib.error |
| ② | -import urllib2 |
-import urllib.request, urllib.error |
| ③ | -import urlparse |
-import urllib.parse |
| ④ | -import robotparser |
-import urllib.robotparser |
| ⑤ | +||
| Notes + | Python 2 + | Python 3 + + |
| ① + | import urllib
+ | import urllib.request, urllib.parse, urllib.error
+ |
| ② + | import urllib2
+ | import urllib.request, urllib.error
+ |
| ③ + | import urlparse
+ | import urllib.parse
+ |
| ④ + | import robotparser
+ | import urllib.robotparser
+ |
| ⑤ | |
+from urllib import urlencode
|
| ⑥ | +from urllib.parse import urlencode +||
| ⑥ | |
+from urllib2 import HTTPError
|
urllib module in Python 2 had a variety of functions, including urlopen() for fetching data and splittype(), splithost(), and splituser() for splitting a URL into its constituent parts. These functions have been reorganized more logically within the new urllib package. 2to3 will also change all calls to these functions so they use the new naming scheme.
@@ -268,81 +268,81 @@ from urllib.error import HTTPError
dbmAll the various DBM clones are now in a single package, dbm. If you need a specific variant like GNU DBM, you can import the appropriate module within the dbm package.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| - | import dbm |
-import dbm.ndbm |
| - | import gdbm |
-import dbm.gnu |
| - | import dbhash |
-import dbm.bsd |
| - | import dumbdbm |
-import dbm.dumb |
| + | ||
| Notes + | Python 2 + | Python 3 + + |
| + | import dbm
+ | import dbm.ndbm
+ |
| + | import gdbm
+ | import dbm.gnu
+ |
| + | import dbhash
+ | import dbm.bsd
+ |
| + | import dumbdbm
+ | import dbm.dumb
+ |
|
-import dbm | import dbm
|
xmlrpcXML-RPC is a lightweight method of performing remote RPC calls over HTTP. The XML-RPC client library and several XML-RPC server implementations are now combined in a single package, xmlrpc.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| - | import xmlrpclib |
-import xmlrpc.client |
| + | ||
| Notes + | Python 2 + | Python 3 + + |
| + | import xmlrpclib
+ | import xmlrpc.client
+ |
|
-import xmlrpc.server | import xmlrpc.server
|
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | +||
| Notes + | Python 2 + | Python 3 + + |
| ① | |
-import io |
| ② | + import StringIO +import io
+ | |
| ② | |
-import pickle |
| ③ | -import __builtin__ |
-import builtins |
| ④ | -import copy_reg |
-import copyreg |
| ⑤ | -import Queue |
-import queue |
| ⑥ | -import SocketServer |
-import socketserver |
| ⑦ | -import ConfigParser |
-import configparser |
| ⑧ | -import repr |
-import reprlib |
| ⑨ | -import commands |
-import subprocess | import pickle
+ |
| ③ + | import __builtin__
+ | import builtins
+ |
| ④ + | import copy_reg
+ | import copyreg
+ |
| ⑤ + | import Queue
+ | import queue
+ |
| ⑥ + | import SocketServer
+ | import socketserver
+ |
| ⑦ + | import ConfigParser
+ | import configparser
+ |
| ⑧ + | import repr
+ | import reprlib
+ |
| ⑨ + | import commands
+ | import subprocess
|
cStringIO as StringIO, and if that failed, to import StringIO instead. Do not do this in Python 3; the io module does it for you. It will find the fastest implementation available and use it automatically.
@@ -369,16 +369,16 @@ except ImportError:
+--universaldetector.py
Now suppose that universaldetector.py needs to import the entire constants.py file and one class from mbcharsetprober.py. How do you do it?
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -import constants |
-from . import constants |
| ② | -from mbcharsetprober import MultiByteCharSetProber |
-from .mbcharsetprober import MultiByteCharsetProber |
| Notes + | Python 2 + | Python 3 + + |
| ① + | import constants
+ | from . import constants
+ |
| ② + | from mbcharsetprober import MultiByteCharSetProber
+ | from .mbcharsetprober import MultiByteCharsetProber
|
from . import syntax. The period is actually a relative path from this file (universaldetector.py) to the file you want to import (constants.py). In this case, they are in the same directory, thus the single period. You can also import from the parent directory (from .. import anothermodule) or a subdirectory.
@@ -387,35 +387,35 @@ except ImportError:
next() iterator methodIn Python 2, iterators had a next() method which returned the next item in the sequence. That's still true in Python 3, but there is now also a global next() function that takes an iterator as an argument.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -anIterator.next() |
-next(anIterator) |
| ② | -a_function_that_returns_an_iterator().next() |
-next(a_function_that_returns_an_iterator()) |
| ③ | +||
| Notes + | Python 2 + | Python 3 + + |
| ① + | anIterator.next()
+ | next(anIterator)
+ |
| ② + | a_function_that_returns_an_iterator().next()
+ | next(a_function_that_returns_an_iterator())
+ |
| ③ | |
+ pass
|
| ④ | + pass +||
| ④ | |
-no change |
| ⑤ | + pass +no change + | |
| ⑤ | |
+ an_iterator.next()
|
next() method, you now pass the iterator itself to the global next() function.
@@ -427,25 +427,25 @@ for an_iterator in a_sequence_of_iterators:
filter() global functionIn Python 2, the filter() function returned a list, the result of filtering a sequence through a function that returned True or False for each item in the sequence. In Python 3, the filter() function returns an iterator, not a list.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -filter(a_function, a_sequence) |
-list(filter(a_function, a_sequence)) |
| ② | -list(filter(a_function, a_sequence)) |
-no change |
| ③ | -filter(None, a_sequence) |
-[i for i in a_sequence if i] |
| ④ | -for i in filter(None, a_sequence): |
-no change |
| ⑤ | -[i for i in filter(a_function, a_sequence)] |
-no change |
| Notes + | Python 2 + | Python 3 + + |
| ① + | filter(a_function, a_sequence)
+ | list(filter(a_function, a_sequence))
+ |
| ② + | list(filter(a_function, a_sequence))
+ | no change + |
| ③ + | filter(None, a_sequence)
+ | [i for i in a_sequence if i]
+ |
| ④ + | for i in filter(None, a_sequence):
+ | no change + |
| ⑤ + | [i for i in filter(a_function, a_sequence)]
+ | no change |
2to3 will wrap a call to filter() with a call to list(), which simply iterates through its argument and returns a real list.
@@ -457,25 +457,25 @@ for an_iterator in a_sequence_of_iterators:
map() global functionIn much the same way as filter(), the map() function now returns an iterator. (In Python 2, it returned a list.)
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| ① | -map(a_function, 'PapayaWhip') |
-list(map(a_function, 'PapayaWhip')) |
| ② | -map(None, 'PapayaWhip') |
-list('PapayaWhip') |
| ③ | -map(lambda x: x+1, range(42)) |
-[x+1 for x in range(42)] |
| ④ | -for i in map(a_function, a_sequence): |
-no change |
| ⑤ | -[i for i in map(a_function, a_sequence)] |
-no change |
| Notes + | Python 2 + | Python 3 + + |
| ① + | map(a_function, 'PapayaWhip')
+ | list(map(a_function, 'PapayaWhip'))
+ |
| ② + | map(None, 'PapayaWhip')
+ | list('PapayaWhip')
+ |
| ③ + | map(lambda x: x+1, range(42))
+ | [x+1 for x in range(42)]
+ |
| ④ + | for i in map(a_function, a_sequence):
+ | no change + |
| ⑤ + | [i for i in map(a_function, a_sequence)]
+ | no change |
filter(), in the most basic case, 2to3 will wrap a call to map() with a call to list().
@@ -487,14 +487,14 @@ for an_iterator in a_sequence_of_iterators:
reduce() global function (3.1+)In Python 3, the reduce() function has been removed from the global namespace and placed in the functools module.
| Notes | -Python 2 | -Python 3 | -
|---|---|---|
| - | reduce(a, b, c) |
+|
| Notes + | Python 2 + | Python 3 + + |
| + | reduce(a, b, c)
| |
☞The version of
2to3that shipped with Python 3.0 would not fix thereduce()function automatically. The fix first appeared in the2to3script that shipped with Python 3.1. @@ -502,22 +502,22 @@ reduce(a, b, c)
apply()global functionPython 2 had a global function called
apply(), which took a function f and a list[a, b, c]and returnedf(a, b, c). In Python 3, theapply()function no longer exists. Instead, there is a new function calling syntax that allows you to pass a list and have Python apply the list as the function's arguments.-
- Notes -Python 2 -Python 3 -- ① -- apply(a_function, a_list_of_args)a_function(*a_list_of_args)- ② -- apply(a_function, a_list_of_args, a_dictionary_of_named_args)a_function(*a_list_of_args, **a_dictionary_of_named_args)- ③ -- apply(a_function, a_list_of_args + z)a_function(*a_list_of_args + z)+ ④ -- apply(aModule.a_function, a_list_of_args)aModule.a_function(*a_list_of_args)Notes + Python 2 + Python 3 + + ① + apply(a_function, a_list_of_args)+a_function(*a_list_of_args)+② + apply(a_function, a_list_of_args, a_dictionary_of_named_args)+a_function(*a_list_of_args, **a_dictionary_of_named_args)+③ + apply(a_function, a_list_of_args + z)+a_function(*a_list_of_args + z)+④ + apply(aModule.a_function, a_list_of_args)+aModule.a_function(*a_list_of_args)
- In the simplest form, you can call a function with a list of arguments (an actual list like
[a, b, c]) by prepending the list with an asterisk (*). This is exactly equivalent to the oldapply()function in Python 2. @@ -528,30 +528,30 @@ reduce(a, b, c)
intern()global functionIn Python 2, you could call the
intern()function on a string to intern it as a performance optimization. In Python 3, theintern()function has been moved to thesysmodule.-
- Notes -Python 2 -Python 3 -+ - - intern(aString)sys.intern(aString)Notes + Python 2 + Python 3 + + + intern(aString)+sys.intern(aString)
execstatementJust as the
execstatement. Theexec()function takes a string which contains arbitrary Python code and executes it as if it were just another statement or expression.-
- Notes -Python 2 -Python 3 -- ① -- exec codeStringexec(codeString)- ② -- exec codeString in a_global_namespaceexec(codeString, a_global_namespace)+ ③ -- exec codeString in a_global_namespace, a_local_namespaceexec(codeString, a_global_namespace, a_local_namespace)Notes + Python 2 + Python 3 + + ① + exec codeString+exec(codeString)+② + exec codeString in a_global_namespace+exec(codeString, a_global_namespace)+③ + exec codeString in a_global_namespace, a_local_namespace+exec(codeString, a_global_namespace, a_local_namespace)
- In the simplest form, the
2to3script simply encloses the code-as-a-string in parentheses, sinceexec()is now a function instead of a statement. @@ -561,13 +561,13 @@ reduce(a, b, c)
execfilestatement (3.1+)Like the old
execstatement, the oldexecfilestatement will execute strings as if they were Python code. Whereexectook a string,execfiletook a filename. In Python 3, theexecfilestatement has been eliminated. If you really need to take a file of Python code and execute it (but you're not willing to simply import it), you can accomplish the same thing by opening the file, reading its contents, calling the globalcompile()function to force the Python interpreter to compile the code, and then call the newexec()function.-
- Notes -Python 2 -Python 3 -+ - - execfile("a_filename")exec(compile(open("a_filename").read(), "a_filename", "exec"))Notes + Python 2 + Python 3 + + + execfile("a_filename")+exec(compile(open("a_filename").read(), "a_filename", "exec"))☞The version of
2to3that shipped with Python 3.0 would not fix theexecfilestatement automatically. The fix first appeared in the2to3script that shipped with Python 3.1. @@ -575,16 +575,16 @@ reduce(a, b, c)
reprliterals (backticks)In Python 2, there was a special syntax of wrapping any object in backticks (like
`x`) to get a representation of the object. In Python 3, this capability still exists, but you can no longer use backticks to get it. Instead, use the globalrepr()function.-
- Notes -Python 2 -Python 3 -- ① -- `x`repr(x)+ ② -- `"PapayaWhip" + `2``repr("PapayaWhip" + repr(2))Notes + Python 2 + Python 3 + + ① + `x`+repr(x)+② + `"PapayaWhip" + `2``+repr("PapayaWhip" + repr(2))
- Remember, x can be anything — a class, a function, a module, a primitive data type, etc. The
repr()function works on everything. @@ -593,40 +593,40 @@ reduce(a, b, c)
try...exceptstatementThe syntax for catching exceptions has changed slightly between Python 2 and Python 3.
-
- Notes -Python 2 -Python 3 -① +Notes + Python 2 + Python 3 + + - ① + pass try: import mymodule except ImportError, e - passtry: import mymodule except ImportError as e: - pass② + pass +- ② + pass try: import mymodule except (RuntimeError, ImportError), e - passtry: import mymodule except (RuntimeError, ImportError) as e: - pass③ + pass +- ③ - try: import mymodule except ImportError: - passno change ④ + pass +no change + + pass + ④ - try: import mymodule except: - passno change no change
- Instead of a comma after the exception type, Python 3 uses a new keyword,
as. @@ -640,22 +640,22 @@ except:
raisestatementThe syntax for raising your own exceptions has changed slightly between Python 2 and Python 3.
-
- Notes -Python 2 -Python 3 -- ① -- raise MyExceptionunchanged - ② -- raise MyException, "error message"raise MyException("error message")- ③ -- raise MyException, "error message", a_tracebackraise MyException("error message").with_traceback(a_traceback)+ ④ -- raise "error message"unsupported Notes + Python 2 + Python 3 + + ① + raise MyException+unchanged + ② + raise MyException, "error message"+raise MyException("error message")+③ + raise MyException, "error message", a_traceback+raise MyException("error message").with_traceback(a_traceback)+④ + raise "error message"+unsupported
- In the simplest form, raising an exception without a custom error message, the syntax is unchanged. @@ -666,19 +666,19 @@ except:
throwmethod on generatorsIn Python 2, generators have a
throw()method. Callinga_generator.throw()raises an exception at the point where the generator was paused, then returns the next value yielded by the generator function. In Python 3, this functionality is still available, but the syntax is slightly different.-
- Notes -Python 2 -Python 3 -- ① -- a_generator.throw(MyException)no change - ② -- a_generator.throw(MyException, "error message")a_generator.throw(MyException("error message"))+ ③ -- a_generator.throw("error message")unsupported Notes + Python 2 + Python 3 + + ① + a_generator.throw(MyException)+no change + ② + a_generator.throw(MyException, "error message")+a_generator.throw(MyException("error message"))+③ + a_generator.throw("error message")+unsupported
- In the simplest form, a generator throws an exception without a custom error message. In this case, the syntax has not changed between Python 2 and Python 3. @@ -688,25 +688,25 @@ except:
xrange()global functionIn Python 2, there were two ways to get a range of numbers:
range(), which returned a list, andxrange(), which returned an iterator. In Python 3,range()returns an iterator, andxrange()doesn't exist.-
- Notes -Python 2 -Python 3 -- ① -- xrange(10)range(10)- ② -- a_list = range(10)a_list = list(range(10))- ③ -- [i for i in xrange(10)][i for i in range(10)]- ④ -- for i in range(10):no change + ⑤ -- sum(range(10))no change Notes + Python 2 + Python 3 + + ① + xrange(10)+range(10)+② + a_list = range(10)+a_list = list(range(10))+③ + [i for i in xrange(10)]+[i for i in range(10)]+④ + for i in range(10):+no change + ⑤ + sum(range(10))+no change
- In the simplest case, the
2to3script will simply convertxrange()torange(). @@ -718,19 +718,19 @@ except:
raw_input()andinput()global functionsPython 2 had two global functions for asking the user for input on the command line. The first, called
input(), expected the user to enter a Python expression (and returned the result). The second, calledraw_input(), just returned whatever the user typed. This was wildly confusing for beginners and widely regarded as a “wart” in the language. Python 3 excises this wart by renamingraw_input()toinput(), so it works the way everyone naively expects it to work.-
- Notes -Python 2 -Python 3 -- ① -- raw_input()input()- ② -- raw_input("prompt")input("prompt")+ ③ -- input()eval(input())Notes + Python 2 + Python 3 + + ① + raw_input()+input()+② + raw_input("prompt")+input("prompt")+③ + input()+eval(input())
- In the simplest form,
raw_input()becomesinput(). @@ -740,31 +740,31 @@ except:
func_*function attributesIn Python 2, code within functions can access special attributes about the function itself. In Python 3, these special function attributes have been renamed for consistency with other attributes.
-
- Notes -Python 2 -Python 3 -- ① -- a_function.func_namea_function.__name__- ② -- a_function.func_doca_function.__doc__- ③ -- a_function.func_defaultsa_function.__defaults__- ④ -- a_function.func_dicta_function.__dict__- ⑤ -- a_function.func_closurea_function.__closure__- ⑥ -- a_function.func_globalsa_function.__globals__+ ⑦ -- a_function.func_codea_function.__code__Notes + Python 2 + Python 3 + + ① + a_function.func_name+a_function.__name__+② + a_function.func_doc+a_function.__doc__+③ + a_function.func_defaults+a_function.__defaults__+④ + a_function.func_dict+a_function.__dict__+⑤ + a_function.func_closure+a_function.__closure__+⑥ + a_function.func_globals+a_function.__globals__+⑦ + a_function.func_code+a_function.__code__
- The
__name__attribute (previouslyfunc_name) contains the function's name. @@ -778,16 +778,16 @@ except:
xreadlines()I/O methodIn Python 2, file objects had an
xreadlines()method which returned an iterator that would read the file one line at a time. This was useful inforloops, among other places. In fact, it was so useful, later versions of Python 2 added the capability to file objects themselves.-
- Notes -Python 2 -Python 3 -- ① -- for line in a_file.xreadlines():for line in a_file:+ ② -- for line in a_file.xreadlines(5):no change Notes + Python 2 + Python 3 + + ① + for line in a_file.xreadlines():+for line in a_file:+② + for line in a_file.xreadlines(5):+no change
- If you used to call
xreadlines()with no arguments,2to3will convert it to just the file object. In Python 3, this will accomplish the same thing: read the file one line at a time and execute the body of theforloop. @@ -797,22 +797,22 @@ except:
lambdafunctions that take a tuple instead of multiple parametersIn Python 2, you could define anonymous
lambdafunctions which took multiple parameters by defining the function as taking a tuple with a specific number of items. In effect, Python 2 would “unpack” the tuple into named arguments, which you could then reference (by name) within thelambdafunction. In Python 3, you can still pass a tuple to alambdafunction, but the Python interpreter will not unpack the tuple into named arguments. Instead, you will need to reference each argument by its positional index.-
- Notes -Python 2 -Python 3 -- ① -- lambda (x,): x + f(x)lambda x1: x1[0] + f(x1[0])- ② -- lambda (x, y): x + f(y)lambda x_y: x_y[0] + f(x_y[1])- ③ -- lambda (x, (y, z)): x + y + zlambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]+ ④ -- lambda x, y, z: x + y + zunchanged Notes + Python 2 + Python 3 + + ① + lambda (x,): x + f(x)+lambda x1: x1[0] + f(x1[0])+② + lambda (x, y): x + f(y)+lambda x_y: x_y[0] + f(x_y[1])+③ + lambda (x, (y, z)): x + y + z+lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]+④ + lambda x, y, z: x + y + z+unchanged
- If you had defined a
lambdafunction that took a tuple of one item, in Python 3 that would become alambdawith references to x1[0]. The name x1 is autogenerated by the2to3script, based on the named arguments in the original tuple. @@ -823,39 +823,39 @@ except:Special method attributes
In Python 2, class methods can reference the class object they are defined in, as well as the method object itself.
im_selfis the class instance object; the classim_funcis the function object;im_classis the class ofim_self(for bound methods) or the class that asked for the method (for unbound methods). In Python 3, these special method attributes have been renamed to follow the naming conventions of other attributes.-
- Notes -Python 2 -Python 3 -- - - aClassInstance.aClassMethod.im_funcaClassInstance.aClassMethod.__func__- - - aClassInstance.aClassMethod.im_selfaClassInstance.aClassMethod.__self__+ - - aClassInstance.aClassMethod.im_classaClassInstance.aClassMethod.self.__class__Notes + Python 2 + Python 3 + + + aClassInstance.aClassMethod.im_func+aClassInstance.aClassMethod.__func__++ aClassInstance.aClassMethod.im_self+aClassInstance.aClassMethod.__self__++ aClassInstance.aClassMethod.im_class+aClassInstance.aClassMethod.self.__class__
__nonzero__special class attributeIn Python 2, you could build your own classes that could be used in a boolean context. For example, you could instantiate the class and then use the instance in an
ifstatement. To do this, you defined a special__nonzero__()method which returnedTrueorFalse, and it was called whenever the instance was used in a boolean context. In Python 3, you can still do this, but the name of the method has changed to__bool__().-
- Notes -Python 2 -Python 3 -① +Notes + Python 2 + Python 3 + + - ① + pass class A: def __nonzero__(self): - passclass A: def __bool__(self): - pass② + pass ++ pass + ② - class A: def __nonzero__(self, x, y): - passno change no change
- Instead of
__nonzero__(), Python 3 calls the__bool__()method when evaluating an instance in a boolean context. @@ -864,27 +864,27 @@ except:Octal literals
The syntax for defining base 8 (octal) numbers has changed slightly between Python 2 and Python 3.
-
- Notes -Python 2 -Python 3 -+ - - x = 0755x = 0o755Notes + Python 2 + Python 3 + + + x = 0755+x = 0o755
sys.maxintDue to the integration of the
longandinttypes, thesys.maxintconstant is no longer accurate. Because the value may still be useful in determining platform-specific capabilities, it has been retained but renamed assys.maxsize.-
- Notes -Python 2 -Python 3 -- ① -- from sys import maxintfrom sys import maxsize+ ② -- a_function(sys.maxint)a_function(sys.maxsize)Notes + Python 2 + Python 3 + + ① + from sys import maxint+from sys import maxsize+② + a_function(sys.maxint)+a_function(sys.maxsize)
maxintbecomesmaxsize. @@ -893,27 +893,27 @@ except:
callable()global functionIn Python 2, you could check whether an object was callable (like a function) with the global
callable()function. In Python 3, this global function has been eliminated. To check whether an object is callable, check for the existence of the__call__()special method.-
- Notes -Python 2 -Python 3 -+ - - callable(anything)hasattr(anything, "__call__")Notes + Python 2 + Python 3 + + + callable(anything)+hasattr(anything, "__call__")
zip()global functionIn Python 2, the global
zip()function took any number of sequences and returned a list of tuples. The first tuple contained the first item from each sequence; the second tuple contained the second item from each sequence; and so on. In Python 3,zip()returns an iterator instead of a list.-
- Notes -Python 2 -Python 3 -- ① -- zip(a, b, c)list(zip(a, b, c))+ ② -- d.join(zip(a, b, c))no change Notes + Python 2 + Python 3 + + ① + zip(a, b, c)+list(zip(a, b, c))+② + d.join(zip(a, b, c))+no change
- In the simplest form, you can get the old behavior of the
zip()function by wrapping the return value in a call tolist(), which will run through the iterator thatzip()returns and return a real list of the results. @@ -922,53 +922,53 @@ except:
StandardErrorexceptionIn Python 2,
StandardErrorwas the base class for all built-in exceptions other thanStopIteration,GeneratorExit,KeyboardInterrupt, andSystemExit. In Python 3,StandardErrorhas been eliminated; useExceptioninstead.-
- Notes -Python 2 -Python 3 -- - - x = StandardError()x = Exception()+ - - x = StandardError(a, b, c)x = Exception(a, b, c)Notes + Python 2 + Python 3 + + + x = StandardError()+x = Exception()++ x = StandardError(a, b, c)+x = Exception(a, b, c)
typesmodule constantsThe
typesmodule contains a variety of constants to help you determine the type of an object. In Python 2, it contained constants for all primitive types likedictandint. In Python 3, these constants have been eliminated; just use the primitive type name instead.-
- Notes -Python 2 -Python 3 -- - - types.StringTypebytes- - - types.DictTypedict- - - types.IntTypeint- - - types.LongTypeint- - - types.ListTypelist+ - - types.NoneTypetype(None)Notes + Python 2 + Python 3 + + + types.StringType+bytes++ types.DictType+dict++ types.IntType+int++ types.LongType+int++ types.ListType+list++ types.NoneType+type(None)
isinstance()global function (3.1+)The
isinstance()function checks whether an object is an instance of a particular class or type. In Python 2, you could pass a tuple of types, andisinstance()would returnTrueif the object was any of those types. In Python 3, you can still do this, but passing the same type twice is deprecated.-
- Notes -Python 2 -Python 3 -+ - - isinstance(x, (int, float, int))isinstance(x, (int, float))Notes + Python 2 + Python 3 + + + isinstance(x, (int, float, int))+isinstance(x, (int, float))☞The version of
2to3that shipped with Python 3.0 would not fix these cases ofisinstance()automatically. The fix first appeared in the2to3script that shipped with Python 3.1. @@ -976,33 +976,33 @@ except:
basestringdatatypePython 2 had two string types: Unicode and non-Unicode. But there was also another type,
basestring. It was an abstract type, a superclass for both thestrandunicodetypes. It couldn't be called or instantiated directly, but you could pass it to the globalisinstance()function to check whether an object was either a Unicode or non-Unicode string. In Python 3, there is only one string type, sobasestringhas no reason to exist.-
- Notes -Python 2 -Python 3 -+ - - isinstance(x, basestring)isinstance(x, str)Notes + Python 2 + Python 3 + + + isinstance(x, basestring)+isinstance(x, str)
itertoolsmodulePython 2.3 introduced the
itertoolsmodule, which defined variants of the globalzip(),map(), andfilter()functions that returned iterators instead of lists. In Python 3, those global functions return iterators, so those functions in theitertoolsmodule have been eliminated.-
- Notes -Python 2 -Python 3 -- ① -- itertools.izip(a, b)zip(a, b)- ② -- itertools.imap(a, b)map(a, b)- ③ -- itertools.ifilter(a, b)filter(a, b)+ ④ -- from itertools import imap, izip, foofrom itertools import fooNotes + Python 2 + Python 3 + + ① + itertools.izip(a, b)+zip(a, b)+② + itertools.imap(a, b)+map(a, b)+③ + itertools.ifilter(a, b)+filter(a, b)+④ + from itertools import imap, izip, foo+from itertools import foo
- Instead of
itertools.izip(), just use the globalzip()function. @@ -1013,63 +1013,63 @@ except:
sys.exc_type,sys.exc_value,sys.exc_tracebackPython 2 had three variables in the
sysmodule that you could access while an exception was being handled:sys.exc_type,sys.exc_value,sys.exc_traceback. (Actually, these date all the way back to Python 1.) Ever since Python 1.5, these variables have been deprecated in favor ofsys.exc_info, which is a tuple that contains all three values. In Python 3, these individual variables have finally gone away; you must usesys.exc_info.-
- Notes -Python 2 -Python 3 -- - - sys.exc_typesys.exc_info()[0]- - - sys.exc_valuesys.exc_info()[1]+ - - sys.exc_tracebacksys.exc_info()[2]Notes + Python 2 + Python 3 + + + sys.exc_type+sys.exc_info()[0]++ sys.exc_value+sys.exc_info()[1]++ sys.exc_traceback+sys.exc_info()[2]List comprehensions over tuples
In Python 2, if you wanted to code a list comprehension that iterated over a tuple, you did not need to put parentheses around the tuple values. In Python 3, explicit parentheses are required.
-
- Notes -Python 2 -Python 3 -+ - - [i for i in 1, 2][i for i in (1, 2)]Notes + Python 2 + Python 3 + + + [i for i in 1, 2]+[i for i in (1, 2)]
os.getcwdu()functionPython 2 had a function named
os.getcwd(), which returned the current working directory as a (non-Unicode) string. Because modern file systems can handle directory names in any character encoding, Python 2.3 introducedos.getcwdu(). Theos.getcwdu()function returned the current working directory as a Unicode string. In Python 3, there is only one string type (Unicode), soos.getcwd()is all you need.-
- Notes -Python 2 -Python 3 -+ - - os.getcwdu()os.getcwd()Notes + Python 2 + Python 3 + + + os.getcwdu()+os.getcwd()Metaclasses
In Python 2, you could create metaclasses either by defining the
metaclassargument in the class declaration, or by defining a special class-level__metaclass__attribute. In Python 3, the class-level attribute has been eliminated.-
- Notes -Python 2 -Python 3 -① +Notes + Python 2 + Python 3 + + - ① - class C(metaclass=PapayaMeta): - passunchanged ② + pass +unchanged + - ② + __metaclass__ = PapayaMeta class Whip: - __metaclass__ = PapayaMetaclass Whip(metaclass=PapayaMeta): - pass③ + pass ++ pass ③ + __metaclass__ = PapayaMeta class C(Whipper, Beater): - __metaclass__ = PapayaMetaclass C(Whipper, Beater, metaclass=PapayaMeta): - pass
- Declaring the metaclass in the class declaration worked in Python 2, and it still works the same in Python 3. @@ -1084,19 +1084,19 @@ except:
☞The
2to3script will not fixset()literals by default. To enable this fix, specify -f set_literal on the command line when you call2to3.-
- Notes -Before -After -- - - set([1, 2, 3]){1, 2, 3}- - - set((1, 2, 3)){1, 2, 3}+ - - set([i for i in a_sequence]){i for i in a_sequence}Notes + Before + After + + + set([1, 2, 3])+{1, 2, 3}++ set((1, 2, 3))+{1, 2, 3}++ set([i for i in a_sequence])+{i for i in a_sequence}
buffer()global function (explicit)Python objects implemented in C can export a “buffer interface,” which is a block of memory that is directly readable and writeable without copying. (That is exactly as powerful and scary as it sounds.) In Python 3,
buffer()has been renamed tomemoryview(). (It's a little more complicated than that, but you can almost certainly ignore the differences.) @@ -1104,13 +1104,13 @@ except:☞The
2to3script will not fix thebuffer()function by default. To enable this fix, specify -f buffer on the command line when you call2to3.-
- Notes -Before -After -+ - - x = buffer(y)x = memoryview(y)Notes + Before + After + + + x = buffer(y)+x = memoryview(y)Whitespace around commas (explicit)
Despite being draconian about whitespace for indenting and outdenting, Python is actually quite liberal about whitespace in other areas. Within lists, tuples, sets, and dictionaries, whitespace can appear before and after commas with no ill effects. However, the Python style guide states that commas should be preceded by zero spaces and followed by one. Although this is purely an aesthetic issue (the code works either way, in both Python 2 and Python 3), the
2to3script can optionally fix this for you. @@ -1118,16 +1118,16 @@ except:☞The
2to3script will not fix whitespace around commas by default. To enable this fix, specify -f wscomma on the command line when you call2to3.
| Notes | -Before | -After | -
|---|---|---|
| - | a ,b |
-a, b |
| - | {a :b} |
-{a: b} |
| Notes + | Before + | After + + |
| + | a ,b
+ | a, b
+ |
| + | {a :b}
+ | {a: b}
|
There were a number of common idioms built up in the Python community. Some, like the while 1: loop, date back to Python 1. (Python didn't have a true boolean type until version 2.3, so developers used 1 and 0 instead.) Modern Python programmers should train their brains to use modern versions of these idioms instead.
@@ -1135,27 +1135,27 @@ except:
☞The 2to3 script will not fix common idioms by default. To enable this fix, specify -f idioms on the command line when you call 2to3.
| Notes | -Before | -After | -
|---|---|---|
| + | ||
| Notes + | Before + | After + + |
|
+ do_stuff()
| |
| - | type(x) == T |
-isinstance(x, T) |
| - | type(x) is T |
-isinstance(x, T) |
| + do_stuff() + | ||
| + | type(x) == T
+ | isinstance(x, T)
+ |
| + | type(x) is T
+ | isinstance(x, T)
+ |
|
+do_stuff(a_list)
|
FIXME: once the rest of the book is written, this appendix should contain copious links back to any chapter or section that touches on these features.
So Python is both dynamically typed (because it doesn't use explicit datatype declarations) and strongly typed (because once a variable has a datatype, it actually matters).
If you have experience in other programming languages, this table may help you visualize how Python compares to them:
| Statically typed | Dynamically typed | |
|---|---|---|
| Weakly typed | C, Objective-C | JavaScript, Perl 5, PHP |
| Strongly typed | Pascal, Java | Python, Ruby |
| Statically typed | Dynamically typed + | |
| Weakly typed | C, Objective-C | JavaScript, Perl 5, PHP + |
| Strongly typed | Pascal, Java | Python, Ruby |
I won't bore you with a long finger-wagging speech about the importance of documenting your code. Just know that code is written once but read many times, and the most important audience for your code is yourself, six months after writing it (i.e. after you've forgotten everything but need to fix something). Python makes it easy to write readable code, so take advantage of it. You'll thank me in six months.