blob: 3b5ffbc1e3297a2b5946404b68b1745e0eaefe2e [file] [log] [blame]
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +00001\documentclass{howto}
2
3% $Id$
4
5\title{What's New in Python 2.1}
Andrew M. Kuchling1ae43c42001-01-24 01:11:26 +00006\release{0.04}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +00007\author{A.M. Kuchling}
8\authoraddress{\email{amk1@bigfoot.com}}
9\begin{document}
10\maketitle\tableofcontents
11
12\section{Introduction}
13
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +000014{\large This document is a draft, and is subject to change until
15Python 2.1 is released. Please send any comments, bug reports, or questions,
16no matter how minor, to \email{amk1@bigfoot.com}.
17}
18
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +000019It's that time again... time for a new Python release, version 2.1.
20One recent goal of the Python development team has been to accelerate
21the pace of new releases, with a new release coming every 6 to 9
22months. 2.1 is the first release to come out at this faster pace, with
23the first alpha appearing in January, 3 months after the final version
24of 2.0 was released.
25
26This article explains the new features in 2.1. While there aren't as
27many changes in 2.1 as there were in Python 2.0, there are still some
28pleasant surprises in store. 2.1 is the first release to be steered
29through the use of Python Enhancement Proposals, or PEPs, so most of
30the sizable changes have accompanying PEPs that provide more complete
31documentation and a design rationale for the change. This article
32doesn't attempt to document the new features completely, but simply
33provides an overview of the new features for Python programmers.
34Refer to the Python 2.1 documentation, or to the specific PEP, for
35more details about any new feature that particularly interests you.
36
37Currently 2.1 is available in an alpha release, but the release
38schedule calls for a beta release by late February 2001, and a final
39release in April 2001.
40
41% ======================================================================
42\section{PEP 232: Function Attributes}
43
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +000044In Python 2.1, functions can now have arbitrary
45information attached to them. People were often using docstrings to hold
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +000046information about functions and methods, because the \code{__doc__}
47attribute was the only way of attaching any information to a function.
48For example, in the Zope Web application server, functions are marked
49as safe for public access by having a docstring, and in John Aycock's
50SPARK parsing framework, docstrings hold parts of the BNF grammar to
51be parsed. This overloading is unfortunate, since docstrings are
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +000052really intended to hold a function's documentation, and it
53means you
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +000054can't properly document functions intended for private use in Zope.
55
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +000056Attributes can now be set and retrieved on functions, using the
57regular Python syntax:
58
59\begin{verbatim}
60def f(): pass
61
62f.publish = 1
63f.secure = 1
64f.grammar = "A ::= B (C D)*"
65\end{verbatim}
66
67The dictionary containing attributes can be accessed as
68\member{__dict__}. Unlike the \member{__dict__} attribute of
69class instances, in functions you can actually assign a new dictionary
70to \member{__dict__}, though the new value is restricted to a
71regular Python dictionary; you can't be tricky and set it to a
72\class{UserDict} instance, a DBM file, or any other random mapping
73object.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +000074
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +000075\begin{seealso}
76
77\seepep{232}{Function Attributes}{Written and implemented by Barry Warsaw.}
78
79\end{seealso}
80
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +000081% ======================================================================
82\section{PEP 207: Rich Comparisons}
83
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +000084In earlier versions, Python's support for implementing comparisons on
85user-defined classes and extension types was quite simple. Classes
86could implement a \method{__cmp__} method that was given two instances
87of a class, and could only return 0 if they were equal or +1 or -1 if
88they weren't; the method couldn't raise an exception or return
89anything other than a Boolean value. Users of Numeric Python often
90found this model too weak and restrictive, because in the
91number-crunching programs that numeric Python is used for, it would be
92more useful to be able to perform elementwise comparisons of two
93matrices, returning a matrix containing the results of a given
94comparison for each element. If the two matrices are of different
95sizes, then the compare has to be able to raise an exception to signal
96the error.
97
98In Python 2.1, rich comparisons were added in order to support this need.
99Python classes can now individually overload each of the \code{<},
100\code{<=}, \code{>}, \code{>=}, \code{==}, and \code{!=} operations.
101The new magic method names are:
102
103\begin{tableii}{c|l}{code}{Operation}{Method name}
104 \lineii{<}{\method{__lt__}}
105 \lineii{<=}{\method{__le__}}
106 \lineii{>}{\method{__gt__}}
107 \lineii{>=}{\method{__ge__}}
108 \lineii{==}{\method{__eq__}}
109 \lineii{!=}{\method{__ne__}}
110\end{tableii}
111
112(The magic methods are named after the corresponding Fortran operators
113\code{.LT.}. \code{.LE.}, \&c. Numeric programmers are almost
114certainly quite familar with these names and will find them easy to
115remember.)
116
117Each of these magic methods is of the form \code{\var{method}(self,
118other)}, where \code{self} will be the object on the left-hand side of
119the operator, while \code{other} will be the object on the right-hand
120side. For example, the expression \code{A < B} will cause
121\code{A.__lt__(B)} to be called.
122
123Each of these magic methods can return anything at all: a Boolean, a
124matrix, a list, or any other Python object. Alternatively they can
125raise an exception if the comparison is impossible, inconsistent, or
126otherwise meaningless.
127
128The built-in \function{cmp(A,B)} function can use the rich comparison
129machinery, and now accepts an optional argument specifying which
130comparison operation to use; this is given as one of the strings
131\code{"<"}, \code{"<="}, \code{">"}, \code{">="}, \code{"=="}, or
132\code{"!="}. If called without the optional third argument,
133\function{cmp()} will only return -1, 0, or +1 as in previous versions
134of Python; otherwise it will call the appropriate method and can
135return any Python object.
136
137There are also corresponding changes of interest to C programmers;
138there's a new slot \code{tp_richcmp} in type objects and an API for
139performing a given rich comparison. I won't cover the C API here, but
140will refer you to PEP 207, or the documentation for Python's C API,
141for the full list of related functions.
142
143\begin{seealso}
144
145\seepep{207}{Rich Comparisions}{Written by Guido van Rossum, heavily
146based on earlier work by David Ascher, and implemented by Guido van Rossum.}
147
148\end{seealso}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000149
150% ======================================================================
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000151\section{PEP 230: Warning Framework}
152
153Over its 10 years of existence, Python has accumulated a certain
154number of obsolete modules and features along the way. It's difficult
155to know when a feature is safe to remove, since there's no way of
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000156knowing how much code uses it --- perhaps no programs depend on the
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000157feature, or perhaps many do. To enable removing old features in a
158more structured way, a warning framework was added. When the Python
159developers want to get rid of a feature, it will first trigger a
160warning in the next version of Python. The following Python version
161can then drop the feature, and users will have had a full release
162cycle to remove uses of the old feature.
163
164Python 2.1 adds the warning framework to be used in this scheme. It
165adds a \module{warnings} module that provide functions to issue
166warnings, and to filter out warnings that you don't want to be
167displayed. Third-party modules can also use this framework to
168deprecate old features that they no longer wish to support.
169
170For example, in Python 2.1 the \module{regex} module is deprecated,
171so importing it causes a warning to be printed:
172
173\begin{verbatim}
174>>> import regex
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000175__main__:1: DeprecationWarning: the regex module is deprecated; please use the re module
176>>>
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000177\end{verbatim}
178
179Warnings can be issued by calling the \function{warnings.warn} function:
180
181\begin{verbatim}
182warnings.warn("feature X no longer supported")
183\end{verbatim}
184
185The first parameter is the warning message; an additional optional
186parameters can be used to specify a particular warning category.
187
188Filters can be added to disable certain warnings; a regular expression
189pattern can be applied to the message or to the module name in order
190to suppress a warning. For example, you may have a program that uses
191the \module{regex} module and not want to spare the time to convert it
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000192to use the \module{re} module right now. The warning can be
193suppressed by calling
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000194
195\begin{verbatim}
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000196import warnings
197warnings.filterwarnings(action = 'ignore',
198 message='.*regex module is deprecated',
199 category=DeprecationWarning,
200 module = '__main__')
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000201\end{verbatim}
202
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000203This adds a filter that will apply only to warnings of the class
204\class{DeprecationWarning} triggered in the \module{__main__} module, and applies a regular expression to only match the message about the \module{regex} module being deprecated, and will cause such warnings to be ignored. Warnings can also be printed only once, printed every time the offending code is executed, or turned into exceptions that will cause the program to stop (unless the exceptions are caught in the usual way, of course).
205
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000206Functions were also added to Python's C API for issuing warnings;
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000207refer to PEP 230 or to Python's API documentation for the details.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000208
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000209\begin{seealso}
210\seepep{5}{Guidelines for Language Evolution}{Written by Paul Prescod,
211to specify procedures to be followed when removing old features from
212Python. The policy described in this PEP hasn't been officially
213adopted, but the eventual policy probably won't be too different from
214Prescod's proposal.}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000215
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000216\seepep{230}{Warning Framework}{Written and implemented by Guido van Rossum.}
217\end{seealso}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000218
219% ======================================================================
220\section{PEP 229: New Build System}
221
222When compiling Python, the user had to go in and edit the
223\file{Modules/Setup} file in order to enable various additional
224modules; the default set is relatively small and limited to modules
225that compile on most Unix platforms. This means that on Unix
226platforms with many more features, most notably Linux, Python
227installations often don't contain all useful modules they could.
228
229Python 2.0 added the Distutils, a set of modules for distributing and
230installing extensions. In Python 2.1, the Distutils are used to
231compile much of the standard library of extension modules,
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000232autodetecting which ones are supported on the current machine. It's
233hoped that this will make Python installations easier and more
234featureful.
235
236Instead of having to edit the \file{Modules/Setup} file in order to
237enable modules, a \file{setup.py} script in the top directory of the
238Python source distribution is run at build time, and attempts to
239discover which modules can be enabled by examining the modules and
240header files on the system. In 2.1alpha1, there's very little you can
241do to change \file{setup.py}'s behaviour, or to discover why a given
242module isn't compiled. If you run into problems in 2.1alpha1, please
243report them, and be prepared to dive into \file{setup.py} in order to
244fix autodetection of a given library on your system. In the alpha2
245release I plan to add ways to have more control over what the script
246does (probably command-line arguments to \file{configure} or to
247\file{setup.py}).
248
249If it turns out to be impossible to make autodetection work reliably,
250it's possible that this change may become an optional build method
251instead of the default, or it may even be backed out completely.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000252
Andrew M. Kuchling4308d3c2001-01-29 17:36:53 +0000253In another far-reaching change to the build mechanism, Neil
254Schemenauer restructured things so Python now uses a single makefile
255that isn't recursive, instead of makefiles in the top directory and in
256each of the Python/, Parser/, Objects/, and Modules/ subdirectories.
257This makes building Python faster, and also makes the build process
258clearer and simpler.
259
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000260\begin{seealso}
261\seepep{229}{Using Distutils to Build Python}{Written and implemented by A.M. Kuchling.}
262\end{seealso}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000263
264% ======================================================================
265\section{PEP 217: Interactive Display Hook}
266
267When using the Python interpreter interactively, the output of
268commands is displayed using the built-in \function{repr()} function.
269In Python 2.1, the variable \module{sys.displayhook} can be set to a
270callable object which will be called instead of \function{repr()}.
271For example, you can set it to a special pretty-printing function:
272
273\begin{verbatim}
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000274>>> # Create a recursive data structure
275... L = [1,2,3]
276>>> L.append(L)
277>>> L # Show Python's default output
278[1, 2, 3, [...]]
279>>> # Use pprint.pprint() as the display function
280... import sys, pprint
281>>> sys.displayhook = pprint.pprint
282>>> L
283[1, 2, 3, <Recursion on list with id=135143996>]
284>>>
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000285\end{verbatim}
286
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000287\begin{seealso}
288
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000289\seepep{217}{Display Hook for Interactive Use}{Written and implemented by Moshe Zadka.}
290
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000291\end{seealso}
292
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000293% ======================================================================
294\section{PEP 208: New Coercion Model}
295
296How numeric coercion is done at the C level was significantly
297modified. This will only affect the authors of C extensions to
298Python, allowing them more flexibility in writing extension types that
299support numeric operations.
300
301Extension types can now set the type flag
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +0000302\code{Py_TPFLAGS_CHECKTYPES} in their \code{PyTypeObject}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000303structure to indicate that they support the new coercion model. In
304such extension types, the numeric slot functions can no longer assume
305that they'll be passed two arguments of the same type; instead they
306may be passed two arguments of differing types, and can then perform
307their own internal coercion. If the slot function is passed a type it
308can't handle, it can indicate the failure by returning a reference to
309the \code{Py_NotImplemented} singleton value. The numeric functions
310of the other type will then be tried, and perhaps they can handle the
311operation; if the other type also returns \code{Py_NotImplemented},
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +0000312then a \exception{TypeError} will be raised. Numeric methods written
313in Python can also return \code{Py_NotImplemented}, causing the
314interpreter to act as if the method did not exist (perhaps raising a
315\exception{TypeError}, perhaps trying another object's numeric
316methods).
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000317
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000318\begin{seealso}
319
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000320\seepep{208}{Reworking the Coercion Model}{Written and implemented by
321Neil Schemenauer, heavily based upon earlier work by Marc-Andr\'e
322Lemburg. Read this to understand the fine points of how numeric
323operations will now be processed at the C level.}
324
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000325\end{seealso}
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000326
327% ======================================================================
328\section{Minor Changes and Fixes}
329
330There were relatively few smaller changes made in Python 2.1 due to
331the shorter release cycle. A search through the CVS change logs turns
332up 57 patches applied, and 86 bugs fixed; both figures are likely to
333be underestimates. Some of the more notable changes are:
334
335\begin{itemize}
336
337
338\item The speed of line-oriented file I/O has been improved because
339people often complain about its lack of speed, and because it's often
340been used as a na\"ive benchmark. The \method{readline()} method of
341file objects has therefore been rewritten to be much faster. The
342exact amount of the speedup will vary from platform to platform
343depending on how slow the C library's \function{getc()} was, but is
344around 66\%, and potentially much faster on some particular operating
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +0000345systems. Tim Peters did much of the benchmarking and coding for this
346change, motivated by a discussion in comp.lang.python.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000347
348A new module and method for file objects was also added, contributed
349by Jeff Epler. The new method, \method{xreadlines()}, is similar to
350the existing \function{xrange()} built-in. \function{xreadlines()}
351returns an opaque sequence object that only supports being iterated
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +0000352over, reading a line on every iteration but not reading the entire
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000353file into memory as the existing \method{readlines()} method does.
354You'd use it like this:
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000355
356\begin{verbatim}
357for line in sys.stdin.xreadlines():
358 # ... do something for each line ...
359 ...
360\end{verbatim}
361
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +0000362For a fuller discussion of the line I/O changes, see the python-dev
363summary for January 1-15, 2001.
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000364
365\item A new method, \method{popitem()}, was added to dictionaries to enable
366destructively iterating through the contents of a dictionary; this can be faster for large dictionaries because .
367\code{D.popitem()} removes a random \code{(\var{key}, \var{value})} pair
368from the dictionary and returns it as a 2-tuple. This was implemented
369mostly by Tim Peters and Guido van Rossum, after a suggestion and
370preliminary patch by Moshe Zadka.
Andrew M. Kuchling4308d3c2001-01-29 17:36:53 +0000371
372% Not checked into CVS yet -- only proposed
373%\item The \operator{in} operator now works for dictionaries
374%XXX 'if key in dict' now works.
375(Thomas Wouters)
376
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000377
378\item \module{curses.panel}, a wrapper for the panel library, part of
379ncurses and of SYSV curses, was contributed by Thomas Gellekum. The
380panel library provides windows with the additional feature of depth.
381Windows can be moved higher or lower in the depth ordering, and the
382panel library figures out where panels overlap and which sections are
383visible.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000384
385\item Modules can now control which names are imported when \code{from
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000386\var{module} import *} is used, by defining an \code{__all__} attribute
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000387containing a list of names that will be imported. One common
388complaint is that if the module imports other modules such as
389\module{sys} or \module{string}, \code{from \var{module} import *}
390will add them to the importing module's namespace. To fix this,
391simply list the public names in \code{__all__}:
392
393\begin{verbatim}
394# List public names
395__all__ = ['Database', 'open']
396\end{verbatim}
397
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000398A stricter version of this patch was first suggested and implemented
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000399by Ben Wolfson, but after some python-dev discussion, a weaker
400final version was checked in.
Andrew M. Kuchlingb216ab62001-01-22 16:15:44 +0000401
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000402\item The PyXML package has gone through a few releases since Python
4032.0, and Python 2.1 includes an updated version of the \module{xml}
404package. Some of the noteworthy changes include support for Expat
4051.2, the ability for Expat parsers to handle files in any encoding
406supported by Python, and various bugfixes for SAX, DOM, and the
407\module{minidom} module.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000408
Andrew M. Kuchlingf228fd12001-01-22 17:52:19 +0000409\item Various functions in the \module{time} module, such as
410\function{asctime()} and \function{localtime()},
411require a floating point argument containing the time in seconds since
412the epoch. The most common use of these functions is to work with the
413current time, so the floating point argument has been made optional;
414when a value isn't provided, the current time will be used. For
415example, log file entries usually need a string containing the current
416time; in Python 2.1, \code{time.asctime()} can be used, instead of the
417lengthier \code{time.asctime(time.localtime(time.time()))} that was
418previously required.
419
420This change was proposed and implemented by Thomas Wouters.
421
Andrew M. Kuchling4308d3c2001-01-29 17:36:53 +0000422\item XXX Characters in repr() of strings now use hex escapes, and
423use \n,\t,\r for those characters (Ka-Ping Yee)
424
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000425\item The \module{ftplib} module now defaults to retrieving files in passive mode,
426because passive mode is more likely to work from behind a firewall.
427This request came from the Debian bug tracking system, since other
428Debian packages use \module{ftplib} to retrieve files and then don't
429work from behind a firewall. It's deemed unlikely that this will
430cause problems for anyone, because Netscape defaults to passive mode
431and few people complain, but if passive mode is unsuitable for your
432application or network setup, call
433\method{set_pasv(0)} on FTP objects to disable passive mode.
434
Andrew M. Kuchlingd9751962001-01-24 00:52:56 +0000435\item The size of the Unicode character database was compressed by another 340K thanks to Fredrik Lundh.
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000436
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000437\end{itemize}
438
439And there's the usual list of bugfixes, minor memory leaks, docstring
440edits, and other tweaks, too lengthy to be worth itemizing; see the
441CVS logs for the full details if you want them.
442
443
444% ======================================================================
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000445\section{Nested Scopes}
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000446
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000447% XXX
448The PEP for this new feature hasn't been completed yet, and the
449requisite changes haven't been checked into CVS yet.
450
451\begin{seealso}
452
453\seepep{227}{Statically Nested Scopes}{Written and implemented by Jeremy Hylton.}
454
455\end{seealso}
456
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000457
458% ======================================================================
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000459\section{Weak References}
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000460
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000461% XXX
462The PEP for this new feature hasn't been completed yet, and the
463requisite changes haven't been checked into CVS yet.
464
465
466\begin{seealso}
467
Andrew M. Kuchling4308d3c2001-01-29 17:36:53 +0000468\seepep{205}{Weak References}{Written and implemented by Fred L. Drake, Jr.}
Andrew M. Kuchlingf33c1182001-01-23 02:48:26 +0000469
470\end{seealso}
471
Andrew M. Kuchling91834c62001-01-22 19:51:13 +0000472
473% ======================================================================
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000474\section{Acknowledgements}
475
Andrew M. Kuchlingd9751962001-01-24 00:52:56 +0000476The author would like to thank the following people for offering suggestions
Andrew M. Kuchling1ae43c42001-01-24 01:11:26 +0000477on various drafts of this article: Graeme Cross,
478David Goodger, Jay Graves, Michael Hudson,
Andrew M. Kuchlingd9751962001-01-24 00:52:56 +0000479Marc-Andr\'e Lemburg, Fredrik Lundh, Neil Schemenauer, Thomas Wouters.
Andrew M. Kuchling90cecee2001-01-22 04:02:09 +0000480
481\end{document}