< BACKMake Note | Bookmark 
156135250194107072078175030179198180025031194137176049106218111004226062067026184135228051

What's New in Python 2.0?

Introduction

During the creation process of this text, the Python development team has been hard at work producing Python 2.0, which at press time, is finally being released to the public.

The supplementary CD-ROM in the back of the book contains the three most current releases of Python: 1.5.2, 1.6, and 2.0, including the most recent Java version of the Python interpreter, JPython (a.k.a. Jython): 1.1.

1.5.2 has been a rock stable release for almost two years, and is the foundation for most of the content in the book. 1.6 brought many new changes to Python. String methods and Unicode support have been added, as well as an improved regular expression engine.

A few more significant changes have made their way into the 2.0 release, which we will address here. We also recommend the "What's New in 2.0" document found at the Python 2.0 Web site (see the Online Resources section of the Appendix for the URL).

Review and Preview

The following is a review of the major changes from Python 1.5.2 to 1.6, along with the expected bug fixes and module updates (new, revised, and obsoleted modules).

  • Unicode support

  • String methods

  • Upgraded regular expression engine (performance and Unicode enhancements)

  • New function invocation mechanism

The 2.0 release also features the usual fixes and module updates, but in addition, offers the following new features to the language:

  • Augmented assignment

  • List comprehensions

  • Extended import statement

  • Extended print statement

Once you get Python 2.0 compiled and/or installed on your system, you will see the familiar start-up line in UNIX (or similar if you are using another platform):

					
% python
Python 2.0 (#4, Oct  2 2000, 23:58:52)
[GCC 2.95.1 19990816 (release)] on sunos5
Type "copyright", "credits" or "license" for more
information.
>>>

				

Now, let's take a look at some of those new features.

Augmented Assignment

Augmented assignment refers to the use of operators, which imply both an arithmetic operation as well as an assignment. You will recognize the following symbols if you are a C, C++, or Java programmer:

					
+=        -=         *=        /=         %=        **=
<<=       >>=           &=        ^=         |=

				

For example, the shorter

					
A += B

				

can now be used instead of

					
A = A + B

				

Other than the obvious syntactical change, the most significant difference is that the first object (A in our example) is examined only once. Mutable objects will be modified in place, whereas immutable objects will have the same effect as "A = A + B" (with a new object allocated) except that A is only evaluated once, as we have mentioned before.

					
>>> m = 12
>>> m %= 7
>>> m
5
>>> m **= 2
>>> m
25
>>> aList = [123, 'xyz']
>>> aList += [45.6e7]
>>> aList
[123, 'xyz', 456000000.0]

				

These in-place operators have equivalent special method names when creating classes to emulate numeric types. To implement an in-place special method, just add an "i" in front of the not-in-place operator; e.g., implement __iadd__() for the += operator as opposed to __add__() for just the + operator.

List Comprehensions

Remember how we used lambda functions along with map() and filter() to apply an operation to list members or to filter out list members based on criteria via a conditional expression? Well, list comprehensions simplify that task and improve performance by bypassing the necessity of using lambda along with functional programming built-in functions. List comprehensions allow you to provide an operation directly with an iteration over the original list sequence.

Let's take a look at the simpler list comprehension syntax first:

					
[ expression
						for
						iterative_var
						in
						sequence ]

				

The core of this statement is the for loop, which iterates over each item of sequence. The prefixed expression is applied for each member of the sequence, and the resulting values comprise the list that the expression yields. The iteration variable need not be part of the expression.

Recall the following code seen earlier in the text (Chapter 11, Functions) which utilizes a lambda function to square the members of a sequence:

					
>>> map(( lambda x: x ** 2), range(6))
[0, 1, 4, 9, 16, 25]

				

We can replace this code with the following list comprehension statement:

					
>>> [ x ** 2 for x in range(6) ]
[0, 1, 4, 9, 16, 25]

				

In the new statement, only one function call (range()) is made (as opposed to three—range(), map(), and the lambda function). You may also use parentheses around the expression if "[ (x ** 2) for x in range(6) ]" is easier for you to read. This syntax for list comprehensions can be a substitute for and is more efficient than using the map() built-in function along with lambda.

List comprehensions also support an extended syntax with the if statement:

					
[ expression
						for
						iterative_var
						in
						sequence
						if
						cond_expression]

				

This syntax will filter or "capture" sequence members only if they meet the condition provided for in the cond_expression conditional expression during iteration.

Recall the following odd() function below, which determines whether a numeric argument is odd or even (returning 1 for odd numbers and 0 for even numbers):

					
def odd(n):
    return n % 2

				

We were able to take the core operation from this function, and use it with filter() and lambda to obtain the set of odd numbers from a sequence:

					
>>> seq = [11, 10, 9, 9, 10, 10, 9, 8, 23, 9, 7, 18, 12, 11, 12]
>>> filter(lambda x: x % 2, seq)
[11, 9, 9, 9, 23, 9, 7, 11]

				

As in the previous example, we can bypass the use of filter() and lambda to obtain the desired set of numbers with list comprehensions:

					
>>> [ x for x in seq if x % 2 ]
[11, 9, 9, 9, 23, 9, 7, 11]

				

List comprehensions also support multiple nested for loops and more than one if clause. Please see the documentation including the "What's New" online document for more information.

Extended import Statement

Another fairly common request from Python programmers is the ability to import modules and module attributes into your program using names other than their original given names. One common workaround is to assign the module name to a variable:

					
>>> import longmodulename
>>> short = longmodulename
>>> del longmodulename

				

In the example above, rather than using longmodulename.attribute, you would use the short.attribute to access the same object. (A similar analogy can be made with importing module attributes using from-import… see below.) However, to do this over and over again, and in multiple modules can be annoying and seem wasteful. The new extended import statement will now support the following:

					
>>> import longmodulename as short

				

Accordingly, you may also use this syntax with from-import statements.

					
>>> from sys import stderr as err
>>> err.write("now using sys.stderr")
now using sys.stderr

				

We will note that as is not a new keyword and is only recognized when using import. As a result, you can still use it as a valid identifier in your code:

					
>>> as = 14
>>> as += 3
>>> as
17

				

Extended print Statement

One of the last and more argumentative additions to Python 2.0 is the extended print statement. The change, which employs a pair of "greater than" symbols (>>), allows you to direct the output of print to a file other than standard output.

In the example below, we utilize our import of sys.stderr to err above:

					
>>> print >> err, "using sys.stderr again"
using sys.stderr again

				

Conclusion

While both augmented assignments and list comprehensions appear to be adding a twist to Python's easygoing syntax, the basic philosophy of keeping the language clean and simple has not changed. The key value-adds that these new features bring to the table is actually under the covers.

Augmented assignment only evaluates the first object once—a timesaver and performance enhancer over the long haul. Also, because function objects created by lambda are practically the same as those generated by def, the overhead of a real function call is incurred when they are executed. By using list comprehensions, there is no additional function object created on the fly, nor is there the additional function call overhead present. In this sense, list comprehensions give Python more "inlined" execution.

The extended import and print statements have less to do with performance as they do with programmer convenience.

Other additions include an optional garbage collector that can detect cycles and improved XML support (xml.dom, xml.sax, xml.parsers, and pyexpat modules). Other features to look for in 2.0 are range displays, parallel for loops, and ports to 64-bit systems.

Exercise

Q:

Create a composite list comprehension statement that creates (randomly) a list of between 1 and 10 random numbers, ranging from 1 to 100, and pull out only the odd ones.

A:

Answer:

Our solution uses list comprehensions as well as the new extended import syntax.

								
>>> from random import randint as ri
>>> [ y for y in [ ri(1, 100) for x in range(ri(1, 10)) ] if y % 2]
[47, 9, 85]
>>> [ y for y in [ ri(1, 100) for x in range(ri(1, 10)) ] if y % 2]
[45, 3]
>>> [ y for y in [ ri(1, 100) for x in range(ri(1, 10)) ] if y % 2]
[]
>>> [ y for y in [ ri(1, 100) for x in range(ri(1, 10)) ] if y % 2]
[47, 25, 95, 83, 15, 77]

							


Last updated on 9/14/2001
Core Python Programming, © 2002 Prentice Hall PTR

< BACKMake Note | Bookmark 

© 2002, O'Reilly & Associates, Inc.