From 3d9df8a3aa681057e963f16779556d7101702d89 Mon Sep 17 00:00:00 2001 From: Mark Pilgrim Date: Sun, 1 Feb 2009 01:03:44 -0500 Subject: [PATCH] finished 2to3 chapter --- index.html | 14 +- porting-code-to-python-3-with-2to3.html | 324 ++++++++++++------------ 2 files changed, 164 insertions(+), 174 deletions(-) diff --git a/index.html b/index.html index d5d5190..fe29e5e 100644 --- a/index.html +++ b/index.html @@ -282,9 +282,10 @@ h3{margin-left:3.5em}
  • exec statement
  • execfile statement (3.1+)
  • repr literals (backticks) +
  • Exceptions
  • try...except statement
  • raise statement -
  • throw statement +
  • throw method on generators
  • xrange() global function
  • raw_input() and input() global functions
  • func_* function attributes @@ -305,10 +306,13 @@ h3{margin-left:3.5em}
  • List comprehensions over tuples
  • os.getcwdu() function
  • Metaclasses -
  • set() literals (explicit) -
  • buffer() global function (explicit) -
  • Whitespace around commas (explicit) -
  • Common idioms (explicit) +
  • Matters of style +
      +
    1. set() literals +
    2. buffer() global function +
    3. Whitespace around commas +
    4. Common idioms +

    This site is optimized for Lynx just because fuck you.
    I’m told it also looks good in graphical browsers. diff --git a/porting-code-to-python-3-with-2to3.html b/porting-code-to-python-3-with-2to3.html index ad3f6ad..4f42a34 100644 --- a/porting-code-to-python-3-with-2to3.html +++ b/porting-code-to-python-3-with-2to3.html @@ -34,6 +34,7 @@ h3:before{counter-increment:h3;content:"A." counter(h2) "." counter(h3) ". "}

  • Other modules
  • Relative imports within a package +
  • next() iterator method
  • filter() global function
  • map() global function
  • reduce() global function (3.1+) @@ -42,16 +43,16 @@ h3:before{counter-increment:h3;content:"A." counter(h2) "." counter(h3) ". "}
  • exec statement
  • execfile statement (3.1+)
  • repr literals (backticks) +
  • Exceptions
  • try...except statement
  • raise statement -
  • throw statement +
  • throw method on generators
  • xrange() global function
  • raw_input() and input() global functions
  • func_* function attributes
  • xreadlines() I/O method
  • lambda functions with multiple parameters
  • Special method attributes -
  • next() iterator method
  • __nonzero__ special class attribute
  • Octal literals
  • sys.maxint @@ -66,10 +67,13 @@ h3:before{counter-increment:h3;content:"A." counter(h2) "." counter(h3) ". "}
  • List comprehensions over tuples
  • os.getcwdu() function
  • Metaclasses -
  • set() literals (explicit) -
  • buffer() global function (explicit) -
  • Whitespace around commas (explicit) -
  • Common idioms (explicit) +
  • Matters of style +
      +
    1. set() literals +
    2. buffer() global function +
    3. Whitespace around commas +
    4. Common idioms +

    Diving in

    Python 3 comes with a utility script called 2to3, which takes your actual Python 2 source code as input and auto-converts as much as it can to Python 3. Case study: porting chardet to Python 3 describes how to run the 2to3 script, then shows some things it can't fix automatically. This appendix documents what it can fix automatically. @@ -252,7 +256,7 @@ h3:before{counter-increment:h3;content:"A." counter(h2) "." counter(h3) ". "}

    Modules that have been renamed or reorganized

    Several modules in the Python Standard Library have been renamed. Several other modules which are related to each other have been combined or reorganized to make their association more logical. -

    http package

    +

    http

    In Python 3, several related HTTP modules have been combined into a single package, http.

    skip over this table @@ -281,7 +285,7 @@ import CGIHttpServer
  • The http.cookiejar module manipulates the actual files on disk that popular web browsers use to store cookies.
  • The http.server module provides a basic HTTP server. -

    urllib package

    +

    urllib

    Python 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.

    skip over this table

  • @@ -320,7 +324,7 @@ from urllib.error import HTTPError
  • The FancyURLopener class, which handles HTTP redirects and other status codes, is still available in the new urllib.request module. The urlencode function has moved to urllib.parse.
  • The Request object is still available in urllib.request, but constants like HTTPError have been moved to urllib.error. -

    dbm package

    +

    dbm

    All 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.

    skip over this table

  • @@ -346,7 +350,7 @@ import whichdb
    import dbm

    -

    xmlrpc package

    +

    xmlrpc

    XML-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.

    skip over this table @@ -446,6 +450,47 @@ except ImportError:
  • When you need to import an entire module from elsewhere in your package, use the new 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.
  • To import a specific class or function from another module directly into your module's namespace, prefix the target module with a relative path, minus the trailing slash. In this case, mbcharsetprober.py is in the same directory as universaldetector.py, so the path is a single period. You can also import form the parent directory (from ..anothermodule import AnotherClass) or a subdirectory. +

    next() iterator method

    +

    In 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. +

    skip over this table +

  • + + + + + + + + + + + + + + + + + + + +
    NotesPython 2Python 3
    anIterator.next()next(anIterator)
    a_function_that_returns_an_iterator().next()next(a_function_that_returns_an_iterator())
    class A:
    +    def next(self):
    +        pass
    class A:
    +    def __next__(self):
    +        pass
    class A:
    +    def next(self, x, y):
    +        pass
    no change
    next = 42
    +for an_iterator in a_sequence_of_iterators:
    +    an_iterator.next()
    next = 42
    +for an_iterator in a_sequence_of_iterators:
    +    an_iterator.__next__()
    +

      +
    1. In the simplest case, instead of calling an iterator's next() method, you now pass the iterator itself to the global next() function. +
    2. If you have a function that returns an iterator, call the function and pass the result to the next() function. (The 2to3 script is smart enough to convert this properly.) +
    3. If you define your own class and mean to use it as an iterator, define the __next__() special method. +
    4. If you define your own class and just happen to have a method named next() that takes one or more arguments, 2to3 will not touch it. This class can not be used as an iterator, because its next() method takes arguments. +
    5. This one is a bit tricky. If you have a local variable named next, then it takes precedence over the new global next() function. In this case, you need to call the iterator's special __next()__ method to get the next item in the sequence. (Alternatively, you could also refactor the code so the local variable wasn't named next, but 2to3 will not do that for you automatically.) +

    filter() global function

    In 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 interator, not a list.

    skip over this table @@ -624,7 +669,7 @@ reduce(a, b, c)

  • In Python 2, backticks could be nested, leading to this sort of confusing (but valid) expression. The 2to3 tool is smart enough to convert this into nested calls to repr().

    try...except statement

    -

    The syntax for catching exceptions has changed slightly between Python 2 and 3. +

    The syntax for catching exceptions has changed slightly between Python 2 and Python 3.

    skip over this table @@ -665,7 +710,7 @@ except:
    1. Instead of a comma after the exception type, Python 3 uses a new keyword, as.
    2. The as keyword also works for catching multiple types of exceptions at once. -
    3. If you catch an exception but don't actually care about accessing the exception object itself, the syntax is identical between Python 2 and 3. +
    4. If you catch an exception but don't actually care about accessing the exception object itself, the syntax is identical between Python 2 and Python 3.
    5. Similarly, if you use a fallback to catch all exceptions, the syntax is identical.
    @@ -699,8 +744,8 @@ except:
  • Python 2 supported a more complex syntax to raise an exception with a custom traceback (stack trace). You can do this in Python 3 as well, but the syntax is quite different.
  • In Python 2, you could raise an exception with no exception class, just an error message. In Python 3, this is no longer possible. 2to3 will warn you that it was unable to fix this automatically. -

    throw statement

    -

    FIXME intro +

    throw method on generators

    +

    In Python 2, generators have a throw() method. Calling a_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.

    skip over this table

  • Notes
    @@ -708,19 +753,19 @@ except: - + - - + + - +
    NotesPython 3
    aGenerator.throw(MyException)a_generator.throw(MyException) no change
    aGenerator.throw(MyException, "error message")aGenerator.throw(MyException("error message"))
    a_generator.throw(MyException, "error message")a_generator.throw(MyException("error message"))
    aGenerator.throw("error message")a_generator.throw("error message") unsupported

      -
    1. ... -
    2. ... -
    3. ... +
    4. 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. +
    5. If the generator throws an exception with a custom error message, you need to pass the error string to the exception when you create it. +
    6. Python 2 also supported throwing an exception with only a custom error message. Python 3 does not support this, and the 2to3 script will display a warning telling you that you will need to fix this code manually.

    xrange() global function

    In Python 2, there were two ways to get a range of numbers: range(), which returned a list, and xrange(), which returned an iterator. In Python 3, range() returns an iterator, and xrange() doesn't exist. @@ -777,7 +822,7 @@ except:

  • If you actually need to ask the user for a Python expression to evaluate, use the input() function and pass the result to eval().

    func_* function attributes

    -

    FIXME intro +

    In 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.

    skip over this table @@ -785,38 +830,38 @@ except: - - + + - - - + + + - - + + - - + +
    NotesPython 3
    a_function.func_closurea_function.__closure__
    a_function.func_namea_function.__name__
    a_function.func_doc a_function.__doc__
    a_function.func_namea_function.__name__
    a_function.func_defaults a_function.__defaults__
    a_function.func_dicta_function.__dict__
    a_function.func_codea_function.__code__
    a_function.func_closurea_function.__closure__
    a_function.func_globals a_function.__globals__
    a_function.func_dicta_function.__dict__
    a_function.func_codea_function.__code__

      -
    1. ... -
    2. ... -
    3. ... -
    4. ... -
    5. ... -
    6. ... -
    7. ... +
    8. The __name__ attribute (previously func_name) contains the function's name. +
    9. The __doc__ attribute (previously func_doc) contains the docstring that you defined in the function's source code. +
    10. The __defaults__ attribute (previously func_defaults) is a tuple containing default argument values for those arguments that have default values. +
    11. The __dict__ attribute (previously func_dict) is the namespace supporting arbitrary function attributes. +
    12. The __closure__ attribute (previously func_closure) is a tuple of cells that contain bindings for the function's free variables. +
    13. The __globals__ attribute (previously func_globals) is a reference to the global namespace of the module in which the function was defined. +
    14. The __code__ attribute (previously func_code) is a code object representing the compiled function body.

    xreadlines() I/O method

    -

    In 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 in for loops, among other places. In fact, it was so useful, later versions of Python 2 [FIXME exact version?] added the capability to file objects themselves. +

    In 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 in for loops, among other places. In fact, it was so useful, later versions of Python 2 added the capability to file objects themselves.

    skip over this table @@ -835,7 +880,7 @@ except:
  • If you used to call xreadlines() with an argument (the number of lines to read at a time), keep doing that. It still works in Python 3, and 2to3 will not change it.

    lambda functions with multiple parameters

    -

    FIXME intro +

    In Python 2, you could define anonymous lambda functions 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 the lambda function. In Python 3, you can still pass a tuple to a lambda function, but the Python interpreter will not unpack the tuple into named arguments. Instead, you will need to reference each argument by its positional index.

    skip over this table

  • Notes
    @@ -844,7 +889,7 @@ except: - + @@ -853,12 +898,12 @@ except:
    Notes
    lambda (x,): x + f(x)lambda x1: x1[0] + f(x1[1])
    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[0] + x_y_z[1][0] + x_y_z[1][1]

      -
    1. ... -
    2. ... -
    3. ... +
    4. If you had defined a lambda function that took a tuple of one item, in Python 3 that would become a lambda with references to x1[0]. The name x1 is autogenerated by the 2to3 script, based on the named arguments in the original tuple. +
    5. A lambda function with a two-item tuple (x, y) gets converted to x_y with positional arguments x_y[0] and x_y[1]. +
    6. The 2to3 script can even handle lambda functions with nested tuples of named arguments. The resulting Python 3 code is a bit unreadable, but it works the same as the old code did in Python 2.

    Special method attributes

    -

    FIXME intro +

    In Python 2, class methods can reference the class object they are defined in, as well as the method object itself. im_self is the class instance object; the class im_func is the function object; im_class is the class of im_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.

    skip over this table @@ -875,54 +920,9 @@ except:
    NotesaClassInstance.aClassMethod.im_class aClassInstance.aClassMethod.self.__class__
    -

      -
    1. ... -
    2. ... -
    3. ... -
    -

    next() iterator method

    -

    In 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. -

    skip over this table - - - - - - - - - - - - - - - - - - - - -
    NotesPython 2Python 3
    anIterator.next()next(anIterator)
    a_function_that_returns_an_iterator().next()next(a_function_that_returns_an_iterator())
    class A:
    -    def next(self):
    -        pass
    class A:
    -    def __next__(self):
    -        pass
    class A:
    -    def next(self, x, y):
    -        pass
    no change
    next = 42
    -for an_iterator in a_sequence_of_iterators:
    -    an_iterator.next()
    next = 42
    -for an_iterator in a_sequence_of_iterators:
    -    an_iterator.__next__()
    -

      -
    1. In the simplest case, instead of calling an iterator's next() method, you now pass the iterator itself to the global next() function. -
    2. If you have a function that returns an iterator, call the function and pass the result to the next() function. (The 2to3 script is smart enough to convert this properly.) -
    3. If you define your own class and mean to use it as an iterator, define the __next__() special method. -
    4. If you define your own class and just happen to have a method named next() that takes one or more arguments, 2to3 will not touch it. This class can not be used as an iterator, because its next() method takes arguments. -
    5. This one is a bit tricky. If you have a local variable named next, then it takes precedence over the new global next() function. In this case, you need to call the iterator's special __next()__ method to get the next item in the sequence. (Alternatively, you could also refactor the code so the local variable wasn't named next, but 2to3 will not do that for you automatically.) -
    +

    __nonzero__ special class attribute

    -

    FIXME intro +

    In 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 if statement. To do this, you defined a special __nonzero__() method which returned True or False, 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__().

    skip over this table @@ -943,8 +943,8 @@ for an_iterator in a_sequence_of_iterators:
    Notesno change

      -
    1. ... -
    2. ... +
    3. Instead of __nonzero__(), Python 3 calls the __bool__() method when evaluating an instance in a boolean context. +
    4. However, if you have a __nonzero__() method that takes arguments, the 2to3 tool will assume that you were using it for some other purpose, and it will not make any changes.

    Octal literals

    The syntax for defining base 8 (octal) numbers has changed slightly between Python 2 and Python 3. @@ -992,7 +992,7 @@ for an_iterator in a_sequence_of_iterators:

    zip() global function

    -

    FIXME intro +

    In 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.

    skip over this table @@ -1007,28 +1007,25 @@ for an_iterator in a_sequence_of_iterators:
    Notesno change

      -
    1. ... -
    2. ... +
    3. In the simplest form, you can get the old behavior of the zip() function by wrapping the return value in a call to list(), which will run through the iterator that zip() returns and return a real list of the results. +
    4. In contexts that already iterate through all the items of a sequence (such as this call to the join() method), the iterator that zip() returns will work just fine. The 2to3 script is smart enough to detect these cases and make no change to your code.
    -

    StandardError() exception

    -

    FIXME intro +

    StandardError exception

    +

    In Python 2, StandardError was the base class for all built-in exceptions other than StopIteration, GeneratorExit, KeyboardInterrupt, and SystemExit. In Python 3, StandardError has been eliminated; use Exception instead.

    skip over this table - + - +
    Notes Python 2 Python 3
    x = StandardError() x = Exception()
    x = StandardError(a, b, c) x = Exception(a, b, c)
    -

      -
    1. ... -
    2. ... -
    +

    types module constants

    The types module contains a variety of constants to help you determine the type of an object. In Python 2, it contained constants for all primitive types like dict and int. In Python 3, these constants have been eliminated; just use the primitive type name instead.

    skip over this table @@ -1087,7 +1084,7 @@ for an_iterator in a_sequence_of_iterators:

    itertools module

    -

    FIXME intro +

    Python 2.3 introduced the itertools module, which defined variants of the global zip(), map(), and filter() functions that returned iterators instead of lists. In Python 3, those global functions return iterators, so those functions in the itertools module have been eliminated. @@ -1103,18 +1100,14 @@ for an_iterator in a_sequence_of_iterators: - - -
    Notes Python 2itertools.ifilter(a, b) filter(a, b)
    itertools.ifilterfalse(a, b)filterfalse(a, b)
    from itertools import imap, izip, foo from itertools import foo

      -
    1. ... -
    2. ... -
    3. ... -
    4. ... -
    5. ... +
    6. Instead of itertools.izip(), just use the global zip() function. +
    7. Instead of itertools.imap(), just use map(). +
    8. itertools.ifilter() becomes filter(). +
    9. The itertools module still exists in Python 3, it just doesn't have the functions that have migrated to the global namespace. The 2to3 script is smart enough to remove the specific imports that no longer exist, while leaving other imports intact.

    sys.exc_type, sys.exc_value, sys.exc_traceback

    Python 2 had three variables in the sys module 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 of sys.exc_info, which is a tuple that contains all three values. In Python 3, these individual variables have finally gone away; you must use sys.exc_info. @@ -1124,19 +1117,19 @@ for an_iterator in a_sequence_of_iterators: 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

    -

    FIXME intro +

    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.

    skip over this table @@ -1149,7 +1142,7 @@ for an_iterator in a_sequence_of_iterators:
    Notes

    os.getcwdu() function

    -

    Python 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 introduced os.getcwdu(). The os.getcwdu() function returned the current working directory as a Unicode string. In Python 3, there is only one string type, so os.getcwd() is all you need. +

    Python 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 introduced os.getcwdu(). The os.getcwdu() function returned the current working directory as a Unicode string. In Python 3, there is only one string type (Unicode), so os.getcwd() is all you need.

    skip over this table @@ -1162,7 +1155,7 @@ for an_iterator in a_sequence_of_iterators:
    Notes

    Metaclasses

    -

    FIXME intro +

    In Python 2, you could create metaclasses either by defining the metaclass argument in the class declaration, or by defining a special class-level __metaclass__ attribute. In Python 3, the class-level attribute has been eliminated.

    skip over this table @@ -1170,22 +1163,29 @@ for an_iterator in a_sequence_of_iterators: + + + - - + -
    NotesPython 3
    class C(metaclass=PapayaMeta):
    +    pass
    unchanged
    class Whip:
         __metaclass__ = PapayaMeta
    class Whip(metaclass=PapayaMeta):
         pass
    class C(Whipper):
    +
    class C(Whipper, Beater):
         __metaclass__ = PapayaMeta
    class C(Whipper, metaclass=PapayaMeta):
    +
    class C(Whipper, Beater, metaclass=PapayaMeta):
         pass

      -
    1. ... -
    2. ... +
    3. Declaring the metaclass in the class declaration worked in Python 2, and it still works the same in Python 3. +
    4. Declaring the metaclass in a class attribute worked in Python 2, but doesn't work in Python 3. +
    5. The 2to3 script is smart enough to construct a valid class declaration, even if the class is inherited from one or more base classes.
    -

    set() literals (explicit)

    -

    FIXME intro +

    Matters of style

    +

    The rest of the “fixes” listed here aren't really fixes per se. That is, the things they change are matters of style, not substance. They work just as well in Python 3 as they do in Python 2, but the developers of Python have a vested interest in making Python code as uniform as possible. To that end, there is an official Python style guide which outlines — in excruciating detail — all sorts of nitpicky details that you almost certainly don't care about. And given that 2to3 provides such a great infrastructure for converting Python code from one thing to another, the authors took it upon themselves to add a few optional features to improve the readability of your Python programs. +

    set() literals (explicit)

    +

    In Python 2, the only way to define a literal set in your code was to call set(a_sequence). This still works in Python 3, but a clearer way of doing it is to use the new set literal notation: curly braces. (Dictionaries are also defined with curly braces, which makes sense once you think about it, because dictionaries are just sets of key-value pairs.)

    The 2to3 script will not fix set() literals by default. To enable this fix, specify -f set_literal on the command line when you call 2to3. @@ -1193,26 +1193,22 @@ for an_iterator in a_sequence_of_iterators:

    skip over this table - - + + - + - + - +
    NotesPython 2Python 3BeforeAfter
    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}
    -

      -
    1. ... -
    2. ... -
    3. ... -
    -

    buffer() global function (explicit)

    -

    FIXME intro +

    +

    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 to memoryview(). (It's a little more complicated than that, but you can almost certainly ignore the differences.)

    The 2to3 script will not fix the buffer() function by default. To enable this fix, specify -f buffer on the command line when you call 2to3. @@ -1220,18 +1216,16 @@ for an_iterator in a_sequence_of_iterators:

    skip over this table - - + + - +
    NotesPython 2Python 3BeforeAfter
    x = buffer(y) x = memoryview(y)
    -

      -
    1. ... -
    -

    Whitespace around commas (explicit)

    -

    FIXME intro +

    +

    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 2to3 script can optionally fix this for you.

    The 2to3 script will not fix whitespace around commas by default. To enable this fix, specify -f wscomma on the command line when you call 2to3. @@ -1239,22 +1233,19 @@ for an_iterator in a_sequence_of_iterators:

    skip over this table - - + + - + - +
    NotesPython 2Python 3BeforeAfter
    a ,b a, b
    {a :b} {a: b}
    -

      -
    1. ... -
    2. ... -
    -

    Common idioms (explicit)

    -

    FIXME intro +

    +

    Common idioms (explicit)

    +

    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.

    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. @@ -1262,33 +1253,28 @@ for an_iterator in a_sequence_of_iterators:

    skip over this table - - + + - + - + - + - +
    NotesPython 2Python 3BeforeAfter
    while 1:
         do_stuff()
    while True:
         do_stuff()
    type(x) == T isinstance(x, T)
    type(x) is T isinstance(x, T)
    a_list = list(a_sequence)
     a_list.sort()
     do_stuff(a_list)
    a_list = sorted(a_sequence)
     do_stuff(a_list)
    -

      -
    1. ... -
    2. ... -
    3. ... -
    4. ... -
    +

    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.

    © 2001-4, 2009 ark Pilgrim, CC-BY-3.0