11 Other Language Changes
Here are all of the changes that Python 2.4 makes to the core Python language.
- Decorators for functions and methods were added (PEP 318).
- Built-in set and frozenset types were
added (PEP 218). Other new built-ins include the reversed(seq) function (PEP 322).
- Generator expressions were added (PEP 289).
- Certain numeric expressions no longer return values restricted to 32 or 64 bits (PEP 237).
- You can now put parentheses around the list of names in a
from module import names
statement (PEP 328). - The dict.update() method now accepts the same
argument forms as the dict constructor. This includes any
mapping, any iterable of key/value pairs, and keyword arguments.
(Contributed by Raymond Hettinger.)
- The string methods ljust(), rjust(), and
center() now take an optional argument for specifying a
fill character other than a space.
(Contributed by Raymond Hettinger.)
- Strings also gained an rsplit() method that
works like the split() method but splits from the end of
the string.
>>> 'www.python.org'.split('.', 1) ['www', 'python.org'] 'www.python.org'.rsplit('.', 1) ['www.python', 'org']
- Three keyword parameters, cmp, key, and
reverse, were added to the sort() method of lists.
These parameters make some common usages of sort() simpler.
All of these parameters are optional.
For the cmp parameter, the value should be a comparison function that takes two parameters and returns -1, 0, or +1 depending on how the parameters compare. This function will then be used to sort the list. Previously this was the only parameter that could be provided to sort().
key should be a single-parameter function that takes a list element and returns a comparison key for the element. The list is then sorted using the comparison keys. The following example sorts a list case-insensitively:
>>> L = ['A', 'b', 'c', 'D'] >>> L.sort() # Case-sensitive sort >>> L ['A', 'D', 'b', 'c'] >>> # Using 'key' parameter to sort list >>> L.sort(key=lambda x: x.lower()) >>> L ['A', 'b', 'c', 'D'] >>> # Old-fashioned way >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) >>> L ['A', 'b', 'c', 'D']
The last example, which uses the cmp parameter, is the old way to perform a case-insensitive sort. It works but is slower than using a key parameter. Using key calls lower() method once for each element in the list while using cmp will call it twice for each comparison, so using key saves on invocations of the lower() method.
For simple key functions and comparison functions, it is often possible to avoid a lambda expression by using an unbound method instead. For example, the above case-insensitive sort is best written as:
>>> L.sort(key=str.lower) >>> L ['A', 'b', 'c', 'D']
Finally, the reverse parameter takes a Boolean value. If the value is true, the list will be sorted into reverse order. Instead of
L.sort() ; L.reverse()
, you can now writeL.sort(reverse=True)
.The results of sorting are now guaranteed to be stable. This means that two entries with equal keys will be returned in the same order as they were input. For example, you can sort a list of people by name, and then sort the list by age, resulting in a list sorted by age where people with the same age are in name-sorted order.
(All changes to sort() contributed by Raymond Hettinger.)
- There is a new built-in function
sorted(iterable) that works like the in-place
list.sort() method but can be used in
expressions. The differences are:
- the input may be any iterable;
- a newly formed copy is sorted, leaving the original intact; and
- the expression returns the new sorted copy
>>> L = [9,7,8,3,2,4,1,6,5] >>> [10+i for i in sorted(L)] # usable in a list comprehension [11, 12, 13, 14, 15, 16, 17, 18, 19] >>> L # original is left unchanged [9,7,8,3,2,4,1,6,5] >>> sorted('Monty Python') # any iterable may be an input [' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y'] >>> # List the contents of a dict sorted by key values >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5) >>> for k, v in sorted(colormap.iteritems()): ... print k, v ... black 4 blue 2 green 3 red 1 yellow 5
(Contributed by Raymond Hettinger.)
- Integer operations will no longer trigger an OverflowWarning.
The OverflowWarning warning will disappear in Python 2.5.
- The interpreter gained a new switch, -m, that
takes a name, searches for the corresponding module on
sys.path
, and runs the module as a script. For example, you can now run the Python profiler withpython -m profile
. (Contributed by Nick Coghlan.) - The eval(expr, globals, locals)
and execfile(filename, globals, locals)
functions and the exec statement now accept any mapping type
for the locals parameter. Previously this had to be a regular
Python dictionary. (Contributed by Raymond Hettinger.)
- The zip() built-in function and itertools.izip()
now return an empty list if called with no arguments.
Previously they raised a TypeError
exception. This makes them more
suitable for use with variable length argument lists:
(Contributed by Raymond Hettinger.)
>>> def transpose(array): ... return zip(*array) ... >>> transpose([(1,2,3), (4,5,6)]) [(1, 4), (2, 5), (3, 6)] >>> transpose([]) []
- Encountering a failure while importing a module no longer leaves
a partially-initialized module object in
sys.modules
. The incomplete module object left behind would fool further imports of the same module into succeeding, leading to confusing errors. (Fixed by Tim Peters.) - None is now a constant; code that binds a new value to
the name "None" is now a syntax error.
(Contributed by Raymond Hettinger.)
11.1 Optimizations
- The inner loops for list and tuple slicing
were optimized and now run about one-third faster. The inner loops
for dictionaries were also optimized, resulting in performance boosts for
keys(), values(), items(),
iterkeys(), itervalues(), and iteritems().
(Contributed by Raymond Hettinger.)
- The machinery for growing and shrinking lists was optimized for
speed and for space efficiency. Appending and popping from lists now
runs faster due to more efficient code paths and less frequent use of
the underlying system realloc(). List comprehensions
also benefit. list.extend() was also optimized and no
longer converts its argument into a temporary list before extending
the base list. (Contributed by Raymond Hettinger.)
- list(), tuple(), map(),
filter(), and zip() now run several times
faster with non-sequence arguments that supply a __len__()
method. (Contributed by Raymond Hettinger.)
- The methods list.__getitem__(),
dict.__getitem__(), and dict.__contains__() are
are now implemented as method_descriptor objects rather
than wrapper_descriptor objects. This form of
access doubles their performance and makes them more suitable for
use as arguments to functionals:
"map(mydict.__getitem__, keylist)".
(Contributed by Raymond Hettinger.)
- Added a new opcode,
LIST_APPEND
, that simplifies the generated bytecode for list comprehensions and speeds them up by about a third. (Contributed by Raymond Hettinger.) - The peephole bytecode optimizer has been improved to
produce shorter, faster bytecode; remarkably, the resulting bytecode is
more readable. (Enhanced by Raymond Hettinger.)
- String concatenations in statements of the form
s = s + "abc"
ands += "abc"
are now performed more efficiently in certain circumstances. This optimization won't be present in other Python implementations such as Jython, so you shouldn't rely on it; using the join() method of strings is still recommended when you want to efficiently glue a large number of strings together. (Contributed by Armin Rigo.)
The net result of the 2.4 optimizations is that Python 2.4 runs the pystone benchmark around 5% faster than Python 2.3 and 35% faster than Python 2.2. (pystone is not a particularly good benchmark, but it's the most commonly used measurement of Python's performance. Your own applications may show greater or smaller benefits from Python 2.4.)
See About this document... for information on suggesting changes.