blob: 4947290bf0fe3c9bbfbe9c0343baf7e2a5b64601 [file] [log] [blame]
Fred Drakeed0fa3d2003-07-30 19:14:09 +00001\documentclass{howto}
2\usepackage{distutils}
3% $Id$
4
5\title{What's New in Python 2.4}
6\release{0.0}
7\author{A.M.\ Kuchling}
8\authoraddress{\email{amk@amk.ca}}
9
10\begin{document}
11\maketitle
12\tableofcontents
13
14This article explains the new features in Python 2.4. No release date
Raymond Hettingerd4462302003-11-26 17:52:45 +000015for Python 2.4 has been set; expect that this will happen mid-2004.
Fred Drakeed0fa3d2003-07-30 19:14:09 +000016
17While Python 2.3 was primarily a library development release, Python
182.4 may extend the core language and interpreter in
19as-yet-undetermined ways.
20
21This article doesn't attempt to provide a complete specification of
22the new features, but instead provides a convenient overview. For
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +000023full details, you should refer to the documentation for Python 2.4,
24such as the \citetitle[../lib/lib.html]{Python Library Reference} and
25the \citetitle[../ref/ref.html]{Python Reference Manual}.
Fred Drakeed0fa3d2003-07-30 19:14:09 +000026If you want to understand the complete implementation and design
27rationale, refer to the PEP for a particular new feature.
28
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +000029
Raymond Hettinger7e0282f2003-11-24 07:14:54 +000030%======================================================================
31\section{PEP 218: Built-In Set Objects}
32
33Two new built-in types, \function{set(iterable)} and
34\function{frozenset(iterable)} provide high speed data types for
35membership testing, for eliminating duplicates from sequences, and
36for mathematical operations like unions, intersections, differences,
37and symmetric differences.
38
39\begin{verbatim}
40>>> a = set('abracadabra') # form a set from a string
41>>> 'z' in a # fast membership testing
42False
43>>> a # unique letters in a
44set(['a', 'r', 'b', 'c', 'd'])
45>>> ''.join(a) # convert back into a string
46'arbcd'
Raymond Hettingerd4462302003-11-26 17:52:45 +000047
Raymond Hettinger7e0282f2003-11-24 07:14:54 +000048>>> b = set('alacazam') # form a second set
49>>> a - b # letters in a but not in b
50set(['r', 'd', 'b'])
51>>> a | b # letters in either a or b
52set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
53>>> a & b # letters in both a and b
54set(['a', 'c'])
55>>> a ^ b # letters in a or b but not both
56set(['r', 'd', 'b', 'm', 'z', 'l'])
Raymond Hettingerd4462302003-11-26 17:52:45 +000057
Raymond Hettinger7e0282f2003-11-24 07:14:54 +000058>>> a.add('z') # add a new element
59>>> a.update('wxy') # add multiple new elements
60>>> a
61set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
62>>> a.remove('x') # take one element out
63>>> a
64set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])
65\end{verbatim}
66
67The type \function{frozenset()} is an immutable version of \function{set()}.
68Since it is immutable and hashable, it may be used as a dictionary key or
69as a member of another set. Accordingly, it does not have methods
70like \method{add()} and \method{remove()} which could alter its contents.
71
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +000072% XXX what happens to the sets module?
Raymond Hettingered54d912003-12-31 01:59:18 +000073% The current thinking is that the sets module will be left alone.
74% That way, existing code will continue to run without alteration.
75% Also, the module provides an autoconversion feature not supported by set()
76% and frozenset().
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +000077
Raymond Hettinger7e0282f2003-11-24 07:14:54 +000078\begin{seealso}
79\seepep{218}{Adding a Built-In Set Object Type}{Originally proposed by
80Greg Wilson and ultimately implemented by Raymond Hettinger.}
81\end{seealso}
Fred Drakeed0fa3d2003-07-30 19:14:09 +000082
83%======================================================================
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +000084\section{PEP 237: Unifying Long Integers and Integers}
85
86XXX write this.
87
88%======================================================================
Andrew M. Kuchling1a420252003-11-08 15:58:49 +000089\section{PEP 322: Reverse Iteration}
Fred Drakeed0fa3d2003-07-30 19:14:09 +000090
Andrew M. Kuchling1a420252003-11-08 15:58:49 +000091A new built-in function, \function{reversed(seq)}, takes a sequence
92and returns an iterator that returns the elements of the sequence
93in reverse order.
94
95\begin{verbatim}
Raymond Hettingerbc3cba22003-11-12 16:39:30 +000096>>> for i in reversed(xrange(1,4)):
Andrew M. Kuchling1a420252003-11-08 15:58:49 +000097... print i
98...
993
1002
1011
102\end{verbatim}
103
Raymond Hettingerbc3cba22003-11-12 16:39:30 +0000104Compared to extended slicing, \code{range(1,4)[::-1]}, \function{reversed()}
105is easier to read, runs faster, and uses substantially less memory.
106
Andrew M. Kuchling1a420252003-11-08 15:58:49 +0000107Note that \function{reversed()} only accepts sequences, not arbitrary
Raymond Hettingerbc3cba22003-11-12 16:39:30 +0000108iterators. If you want to reverse an iterator, first convert it to
109a list with \function{list()}.
Andrew M. Kuchling1a420252003-11-08 15:58:49 +0000110
111\begin{verbatim}
Raymond Hettingered54d912003-12-31 01:59:18 +0000112>>> data = open('/etc/passwd', 'r')
113>>> for line in reversed(list(data)):
Andrew M. Kuchling1a420252003-11-08 15:58:49 +0000114... print line
115...
116root:*:0:0:System Administrator:/var/root:/bin/tcsh
117 ...
118\end{verbatim}
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000119
Andrew M. Kuchlingf7a6b672003-11-08 16:05:37 +0000120\begin{seealso}
121\seepep{322}{Reverse Iteration}{Written and implemented by Raymond Hettinger.}
122
123\end{seealso}
124
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000125
126%======================================================================
127\section{Other Language Changes}
128
129Here are all of the changes that Python 2.4 makes to the core Python
130language.
131
132\begin{itemize}
Raymond Hettingerd4462302003-11-26 17:52:45 +0000133
134\item The string methods, \method{ljust()}, \method{rjust()}, and
Andrew M. Kuchling67087562003-11-26 18:03:48 +0000135\method{center()} now take an optional argument for specifying a
Raymond Hettingerd4462302003-11-26 17:52:45 +0000136fill character other than a space.
137
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000138\item Strings also gained an \method{rsplit()} method that
Raymond Hettingered54d912003-12-31 01:59:18 +0000139works like the \method{split()} method but splits from the end of
140the string. Possible applications include splitting a filename
141from a path or a domain name from URL.
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000142
143\begin{verbatim}
144>>> 'a b c'.split(None, 1)
145['a', 'b c']
146>>> 'a b c'.rsplit(None, 1)
147['a b', 'c']
148\end{verbatim}
149
Andrew M. Kuchling2fb4d512003-10-21 12:31:16 +0000150\item The \method{sort()} method of lists gained three keyword
151arguments, \var{cmp}, \var{key}, and \var{reverse}. These arguments
152make some common usages of \method{sort()} simpler. All are optional.
153
154\var{cmp} is the same as the previous single argument to
155\method{sort()}; if provided, the value should be a comparison
156function that takes two arguments and returns -1, 0, or +1 depending
157on how the arguments compare.
158
159\var{key} should be a single-argument function that takes a list
160element and returns a comparison key for the element. The list is
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000161then sorted using the comparison keys. The following example sorts a
162list case-insensitively:
Andrew M. Kuchling2fb4d512003-10-21 12:31:16 +0000163
164\begin{verbatim}
165>>> L = ['A', 'b', 'c', 'D']
166>>> L.sort() # Case-sensitive sort
167>>> L
168['A', 'D', 'b', 'c']
169>>> L.sort(key=lambda x: x.lower())
170>>> L
171['A', 'b', 'c', 'D']
172>>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
173>>> L
174['A', 'b', 'c', 'D']
175\end{verbatim}
176
177The last example, which uses the \var{cmp} parameter, is the old way
Raymond Hettingered54d912003-12-31 01:59:18 +0000178to perform a case-insensitive sort. It works but is slower than
Andrew M. Kuchling2fb4d512003-10-21 12:31:16 +0000179using a \var{key} parameter. Using \var{key} results in calling the
180\method{lower()} method once for each element in the list while using
181\var{cmp} will call the method twice for each comparison.
182
Andrew M. Kuchling981a9182003-11-13 21:33:26 +0000183For simple key functions and comparison functions, it is often
184possible to avoid a \keyword{lambda} expression by using an unbound
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000185method instead. For example, the above case-insensitive sort is best
186coded as:
187
188\begin{verbatim}
189>>> L.sort(key=str.lower)
190>>> L
191['A', 'b', 'c', 'D']
192\end{verbatim}
193
Andrew M. Kuchling2fb4d512003-10-21 12:31:16 +0000194The \var{reverse} parameter should have a Boolean value. If the value is
195\constant{True}, the list will be sorted into reverse order. Instead
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000196of \code{L.sort(lambda x,y: cmp(y.score, x.score))}, you can now write:
197\code{L.sort(key = lambda x: x.score, reverse=True)}.
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000198
Andrew M. Kuchling981a9182003-11-13 21:33:26 +0000199The results of sorting are now guaranteed to be stable. This means
200that two entries with equal keys will be returned in the same order as
201they were input. For example, you can sort a list of people by name,
202and then sort the list by age, resulting in a list sorted by age where
203people with the same age are in name-sorted order.
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000204
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000205\item There is a new built-in function \function{sorted(iterable)} that works
Raymond Hettinger64958a12003-12-17 20:43:33 +0000206like the in-place \method{list.sort()} method but has been made suitable
207for use in expressions. The differences are:
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000208 \begin{itemize}
Raymond Hettinger7d1dd042003-11-12 16:42:10 +0000209 \item the input may be any iterable;
210 \item a newly formed copy is sorted, leaving the original intact; and
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000211 \item the expression returns the new sorted copy
212 \end{itemize}
Andrew M. Kuchling1a420252003-11-08 15:58:49 +0000213
214\begin{verbatim}
215>>> L = [9,7,8,3,2,4,1,6,5]
Raymond Hettinger64958a12003-12-17 20:43:33 +0000216>>> [10+i for i in sorted(L)] # usable in a list comprehension
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000217[11, 12, 13, 14, 15, 16, 17, 18, 19]
218>>> L = [9,7,8,3,2,4,1,6,5] # original is left unchanged
219[9,7,8,3,2,4,1,6,5]
Raymond Hettingerd4462302003-11-26 17:52:45 +0000220
Raymond Hettinger64958a12003-12-17 20:43:33 +0000221>>> sorted('Monte Python') # any iterable may be an input
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000222[' ', 'M', 'P', 'e', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y']
Raymond Hettingerd4462302003-11-26 17:52:45 +0000223
224>>> # List the contents of a dict sorted by key values
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000225>>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5)
Raymond Hettinger64958a12003-12-17 20:43:33 +0000226>>> for k, v in sorted(colormap.iteritems()):
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000227... print k, v
228...
229black 4
230blue 2
231green 3
232red 1
233yellow 5
234
Andrew M. Kuchling1a420252003-11-08 15:58:49 +0000235\end{verbatim}
236
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000237\item The \function{zip()} built-in function and \function{itertools.izip()}
Andrew M. Kuchling67087562003-11-26 18:03:48 +0000238 now return an empty list instead of raising a \exception{TypeError}
Raymond Hettingered54d912003-12-31 01:59:18 +0000239 exception if called with no arguments. This makes the function more
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000240 suitable for use with variable length argument lists:
241
242\begin{verbatim}
243>>> def transpose(array):
244... return zip(*array)
245...
246>>> transpose([(1,2,3), (4,5,6)])
247[(1, 4), (2, 5), (3, 6)]
248>>> transpose([])
249[]
250\end{verbatim}
Andrew M. Kuchling6aedcfc2003-10-21 12:48:23 +0000251
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000252\end{itemize}
253
254
255%======================================================================
256\subsection{Optimizations}
257
258\begin{itemize}
259
260\item Optimizations should be described here.
261
262\end{itemize}
263
264The net result of the 2.4 optimizations is that Python 2.4 runs the
265pystone benchmark around XX\% faster than Python 2.3 and YY\% faster
266than Python 2.2.
267
268
269%======================================================================
270\section{New, Improved, and Deprecated Modules}
271
272As usual, Python's standard library received a number of enhancements and
273bug fixes. Here's a partial list of the most notable changes, sorted
274alphabetically by module name. Consult the
275\file{Misc/NEWS} file in the source tree for a more
276complete list of changes, or look through the CVS logs for all the
277details.
278
279\begin{itemize}
280
Andrew M. Kuchling69f31eb2003-08-13 23:11:04 +0000281\item The \module{curses} modules now supports the ncurses extension
282 \function{use_default_colors()}. On platforms where the terminal
283 supports transparency, this makes it possible to use a transparent background.
284 (Contributed by J\"org Lehmann.)
Andrew M. Kuchling6aedcfc2003-10-21 12:48:23 +0000285
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000286\item The \module{heapq} module has been converted to C. The resulting
287 ten-fold improvement in speed makes the module suitable for handling
288 high volumes of data.
Andrew M. Kuchling1a420252003-11-08 15:58:49 +0000289
Andrew M. Kuchlingdff9dbd2003-11-20 22:22:19 +0000290\item The \module{imaplib} module now supports IMAP's THREAD command.
291(Contributed by Yves Dionne.)
292
Andrew M. Kuchlingad809552003-12-06 23:19:23 +0000293\item The \module{itertools} module gained a
294 \function{groupby(\var{iterable}\optional{, \var{func}})} function,
295 inspired by the GROUP BY clause from SQL.
296 \var{iterable} returns a succession of elements, and the optional
297 \var{func} is a function that takes an element and returns a key
298 value; if omitted, the key is simply the element itself.
299 \function{groupby()} then groups the elements into subsequences
300 which have matching values of the key, and returns a series of 2-tuples
301 containing the key value and an iterator over the subsequence.
302
303Here's an example. The \var{key} function simply returns whether a
304number is even or odd, so the result of \function{groupby()} is to
305return consecutive runs of odd or even numbers.
306
307\begin{verbatim}
308>>> import itertools
309>>> L = [2,4,6, 7,8,9,11, 12, 14]
310>>> for key_val, it in itertools.groupby(L, lambda x: x % 2):
311... print key_val, list(it)
312...
3130 [2, 4, 6]
3141 [7]
3150 [8]
3161 [9, 11]
3170 [12, 14]
318>>>
319\end{verbatim}
320
Raymond Hettingerfeb78c92003-12-12 13:13:47 +0000321Like its SQL counterpart, \function{groupby()} is typically used with
322sorted input. The logic for \function{groupby()} is similar to the
323\UNIX{} \code{uniq} filter which makes it handy for eliminating,
324counting, or identifying duplicate elements:
325
326\begin{verbatim}
327>>> word = 'abracadabra'
Raymond Hettingered54d912003-12-31 01:59:18 +0000328>>> letters = sorted(word) # Turn string into a sorted list of letters
Raymond Hettinger64958a12003-12-17 20:43:33 +0000329>>> letters
Andrew M. Kuchling4612bc52003-12-16 20:59:37 +0000330['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
Raymond Hettingered54d912003-12-31 01:59:18 +0000331>>> [k for k, g in groupby(letters)] # List unique letters
Raymond Hettingerfeb78c92003-12-12 13:13:47 +0000332['a', 'b', 'c', 'd', 'r']
Raymond Hettingered54d912003-12-31 01:59:18 +0000333>>> [(k, len(list(g))) for k, g in groupby(letters)] # Count letter occurences
Raymond Hettingerfeb78c92003-12-12 13:13:47 +0000334[('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]
Raymond Hettingered54d912003-12-31 01:59:18 +0000335>>> [k for k, g in groupby(letters) if len(list(g)) > 1] # List duplicated letters
Raymond Hettingerfeb78c92003-12-12 13:13:47 +0000336['a', 'b', 'r']
337\end{verbatim}
338
Raymond Hettingered54d912003-12-31 01:59:18 +0000339\item \module{itertools} also gained a function named
340\function{tee(\var{iterator}, \var{N})} that returns \var{N} independent
341iterators that replicate \var{iterator}. If \var{N} is omitted, the
342default is 2.
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000343
344\begin{verbatim}
345>>> L = [1,2,3]
346>>> i1, i2 = itertools.tee(L)
347>>> i1,i2
348(<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>)
Raymond Hettingered54d912003-12-31 01:59:18 +0000349>>> list(i1) # Run the first iterator to exhaustion
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000350[1, 2, 3]
Raymond Hettingered54d912003-12-31 01:59:18 +0000351>>> list(i2) # Run the second iterator to exhaustion
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000352[1, 2, 3]
353>\end{verbatim}
354
355Note that \function{tee()} has to keep copies of the values returned
Raymond Hettingered54d912003-12-31 01:59:18 +0000356by the iterator; in the worst case, it may need to keep all of them.
357This should therefore be used carefully if there the leading iterator
358can run far ahead of the trailing iterator in a long stream of inputs.
359If the separation is large, then it becomes preferrable to use
360\function{list()} instead. When the iterators track closely with one
361another, \function{tee()} is ideal. Possible applications include
362bookmarking, windowing, or lookahead iterators.
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000363
Andrew M. Kuchlingdff9dbd2003-11-20 22:22:19 +0000364\item A new \function{getsid()} function was added to the
365\module{posix} module that underlies the \module{os} module.
366(Contributed by J. Raynor.)
367
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000368\item The \module{operator} module gained two new functions,
369\function{attrgetter(\var{attr})} and \function{itemgetter(\var{index})}.
370Both functions return callables that take a single argument and return
Raymond Hettingered54d912003-12-31 01:59:18 +0000371the corresponding attribute or item; these callables make excellent
372data extractors when used with \function{map()} or \function{sorted()}.
373For example:
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000374
375\begin{verbatim}
Raymond Hettingered54d912003-12-31 01:59:18 +0000376>>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)]
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000377>>> map(operator.itemgetter(0), L)
378['c', 'd', 'a', 'b']
379>>> map(operator.itemgetter(1), L)
Raymond Hettingered54d912003-12-31 01:59:18 +0000380[2, 1, 4, 3]
381>>> sorted(L, key=operator.itemgetter(1)) # Sort list by second tuple item
382[('d', 1), ('c', 2), ('b', 3), ('a', 4)]
Andrew M. Kuchling35f2b052003-12-18 13:28:13 +0000383\end{verbatim}
384
Andrew M. Kuchling6aedcfc2003-10-21 12:48:23 +0000385\item The \module{random} module has a new method called \method{getrandbits(N)}
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000386 which returns an N-bit long integer. This method supports the existing
387 \method{randrange()} method, making it possible to efficiently generate
388 arbitrarily large random numbers (suitable for prime number generation in
Raymond Hettingered54d912003-12-31 01:59:18 +0000389 RSA applications for example).
Andrew M. Kuchling6aedcfc2003-10-21 12:48:23 +0000390
391\item The regular expression language accepted by the \module{re} module
392 was extended with simple conditional expressions, written as
393 \code{(?(\var{group})\var{A}|\var{B})}. \var{group} is either a
394 numeric group ID or a group name defined with \code{(?P<group>...)}
395 earlier in the expression. If the specified group matched, the
396 regular expression pattern \var{A} will be tested against the string; if
397 the group didn't match, the pattern \var{B} will be used instead.
Andrew M. Kuchling69f31eb2003-08-13 23:11:04 +0000398
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000399\end{itemize}
400
401
402%======================================================================
403% whole new modules get described in \subsections here
404
405
406% ======================================================================
407\section{Build and C API Changes}
408
409Changes to Python's build process and to the C API include:
410
411\begin{itemize}
412
Andrew M. Kuchling6aedcfc2003-10-21 12:48:23 +0000413 \item Three new convenience macros were added for common return
414 values from extension functions: \csimplemacro{Py_RETURN_NONE},
415 \csimplemacro{Py_RETURN_TRUE}, and \csimplemacro{Py_RETURN_FALSE}.
416
417 \item A new function, \cfunction{PyTuple_Pack(N, obj1, obj2, ...,
418 objN)}, constructs tuples from a variable length argument list of
419 Python objects.
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000420
Andrew M. Kuchling2ce1d472003-11-26 18:05:26 +0000421 \item A new function, \cfunction{PyDict_Contains(d, k)}, implements
422 fast dictionary lookups without masking exceptions raised during the
423 look-up process.
Raymond Hettingerd4462302003-11-26 17:52:45 +0000424
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000425\end{itemize}
426
427
428%======================================================================
429\subsection{Port-Specific Changes}
430
431Platform-specific changes go here.
432
433
434%======================================================================
435\section{Other Changes and Fixes \label{section-other}}
436
437As usual, there were a bunch of other improvements and bugfixes
438scattered throughout the source tree. A search through the CVS change
439logs finds there were XXX patches applied and YYY bugs fixed between
440Python 2.3 and 2.4. Both figures are likely to be underestimates.
441
442Some of the more notable changes are:
443
444\begin{itemize}
445
446\item Details go here.
447
448\end{itemize}
449
450
451%======================================================================
452\section{Porting to Python 2.4}
453
454This section lists previously described changes that may require
455changes to your code:
456
457\begin{itemize}
458
Raymond Hettinger607c00f2003-11-12 16:27:50 +0000459\item The \function{zip()} built-in function and \function{itertools.izip()}
460 now return an empty list instead of raising a \exception{TypeError}
461 exception if called with no arguments.
Andrew M. Kuchling6aedcfc2003-10-21 12:48:23 +0000462
463\item \function{dircache.listdir()} now passes exceptions to the caller
464 instead of returning empty lists.
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000465
466\end{itemize}
467
468
469%======================================================================
470\section{Acknowledgements \label{acks}}
471
472The author would like to thank the following people for offering
473suggestions, corrections and assistance with various drafts of this
Andrew M. Kuchling981a9182003-11-13 21:33:26 +0000474article: Raymond Hettinger.
Fred Drakeed0fa3d2003-07-30 19:14:09 +0000475
476\end{document}