Python 2.4 有什么新变化
***********************

作者:
   A.M. Kuchling

本文介绍了2005年3月30日发布的 Python 2.4.1 的新功能。

Python 2.4 是一个中等规模的发布版。 它引入的变化没有激进的 Python 2.2
那么多，但比保守的 2.3 发布版引入了更多的特性。 最主要的新语言特性是函
数装饰器和生成器表达式；其他大部分改动都是针对标准库。

根据 CVS 变更日志，Python 2.3 和 2.4 之间共应用了 481 个补丁并修复了
502 个错误。 这两个数字可能都被低估了。

本文并不试图提供每一个新特性的完整规范说明，而是对每个特性进行简要的介
绍。 要了解完整细节，你应该参考 Python 2.4 的文档，如 Python 库参考和
Python 参考手册等。 通常你需要参阅特定新特性的 PEP 以了解有关具体实现
和设计原理的说明。


PEP 218: 内置集合对象
=====================

Python 2.3 引入了 "sets" 模块。 现在集合数据类型的 C 语言实现作为两个
新的内置类型 "set(iterable)" 和 "frozenset(iterable)" 被添加到 Python
内核中。 它们为成员测试、消除序列中的重复数据以及并集、交集、差集和对
称差集等数学运算提供了高速操作。

   >>> a = set('abracadabra')              # form a set from a string
   >>> 'z' in a                            # fast membership testing
   False
   >>> a                                   # unique letters in a
   set(['a', 'r', 'b', 'c', 'd'])
   >>> ''.join(a)                          # convert back into a string
   'arbcd'

   >>> b = set('alacazam')                 # form a second set
   >>> a - b                               # letters in a but not in b
   set(['r', 'd', 'b'])
   >>> a | b                               # letters in either a or b
   set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
   >>> a & b                               # letters in both a and b
   set(['a', 'c'])
   >>> a ^ b                               # letters in a or b but not both
   set(['r', 'd', 'b', 'm', 'z', 'l'])

   >>> a.add('z')                          # add a new element
   >>> a.update('wxy')                     # add multiple new elements
   >>> a
   set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
   >>> a.remove('x')                       # take one element out
   >>> a
   set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])

"frozenset()" 类型是 "set()" 的不可变版本。 由于它是不可变且不可哈希的
对象，因而可被用作字典的键或另一个集合的成员。

"sets" 模块仍被保留在标准库中，如果你想要子类化 "Set" 或
"ImmutableSet" 类时会很有用处。 目前还没有弃用该模块的计划。

参见:

  **PEP 218** - 添加内置Set对象类型
     最初由 Greg Wilson 提出，由 Raymond Hettinger 最终实现。


PEP 237: 统一长整数和整数
=========================

这个PEP的漫长过渡过程始于Python 2.2，在Python 2.4中又向前迈出了一步。
在2.3中，某些在int/long统一后行为不同的整数操作会触发 "FutureWarning"
警告，并返回限于32位或64位（取决于您的平台）的值。在2.4中，这些表达式
不再产生警告，而是产生一个通常为长整数的不同结果。

问题表达式主要是左移和长十六进制和八进制常量。例如，"2 << 32" 在2.3中
会引发警告，在32位平台上评估为0。在Python 2.4中，这个表达式现在返回正
确答案，8589934592。

参见:

  **PEP 237** - 统一长整数和整数
     原始PEP由 Moshe Zadka 和 GvR 撰写，2.4 的变更由 Kalle Svensson 实
     现。


PEP 289: 生成器表达式
=====================

Python 2.2中引入的迭代器特性和 "itertools" 模块使得编写循环遍历大数据
集的程序变得更加容易，而无需将整个数据集一次性加载到内存中。列表推导式
并不很适合这种场景，因为它们会产生一个包含所有项的Python列表对象。这不
可避免地将所有对象拉入内存，如果数据集非常大，这可能会成为问题。当尝试
编写函数式风格的程序时，自然会写出类似以下代码：

   links = [link for link in get_all_links() if not link.followed]
   for link in links:
       ...

代替：

   for link in get_all_links():
       if link.followed:
           continue
       ...

第一种形式更简洁，可能也更易读，但如果你正在处理大量的链接对象，为了避
免同时将所有链接对象加载到内存中，你将不得不编写第二种形式。

生成器表达式的工作方式类似于列表推导式，但不生成整个列表；相反，它们创
建一个生成器，逐个返回元素。上述示例可以改写为：

   links = (link for link in get_all_links() if not link.followed)
   for link in links:
       ...

生成器表达式必须像上述示例那样写在括号内。函数调用所用的括号也算在内，
因此如果你想要创建一个将立即传递给函数的迭代器，可以写成：

   print sum(obj.count for obj in list_all_objects())

生成器表达式与列表推导式在各方面有细微的不同。最显著的是，循环变量（上
述示例中的*obj*）在生成器表达式外部是不可访问的。列表推导式会将变量赋
值为最后一个值；Python的未来版本将改变这一点，使列表推导式在这方面与生
成器表达式一致。

参见:

  **PEP 289** - 生成器表达式
     由Raymond Hettinger提出，Jiwon Seo实现，Hye-Shik Chang在早期进行
     了指导。


PEP 292: 更简单的字符串替换
===========================

标准库中的一些新类提供了将变量替换到字符串中的替代机制；这种替换风格可
能更适合那些未经训练的用户需要编辑模板的应用程序。

按名称替换变量的常用方式是 "%" 运算符:

   >>> '%(page)i: %(title)s' % {'page':2, 'title': 'The Best of Times'}
   '2: The Best of Times'

在编写模板字符串时，很容易忘记在闭合括号后加上 "i" 或 "s"。如果模板在
Python 模块中，这并不是一个大问题，因为你可以运行代码，得到一个“不支持
的格式字符” "ValueError"，然后修复这个问题。然而，考虑像 Mailman 这样
的应用程序，其中模板字符串或翻译是由不了解 Python 语言的用户编辑的。向
这些用户解释格式字符串的语法是很复杂的，如果他们犯了错误，很难向他们提
供有用的反馈。

PEP 292 给 "string" 模块增加了一个 "Template"，它使用 "$" 来表示替换:

   >>> import string
   >>> t = string.Template('$page: $title')
   >>> t.substitute({'page':2, 'title': 'The Best of Times'})
   '2: The Best of Times'

如果某个键在字典中找不到，"substitute()" 方法将引发 "KeyError"。 还有
一个 "safe_substitute()" 方法则会忽略找不到的键:

   >>> t = string.Template('$page: $title')
   >>> t.safe_substitute({'page':3})
   '3: $title'

参见:

  **PEP 292** - 更简单的字符串替换
     由 Barry Warsaw 撰写并实现


PEP 318: 函数和方法的装饰器
===========================

Python 2.2 通过添加静态方法和类方法扩展了 Python 的对象模型，但它并没
有扩展 Python 的语法来提供任何定义静态方法或类方法的新方式。相反，你必
须以通常的方式编写一个 "def" 语句，并将生成的函数传递给一个
"staticmethod()" 或 "classmethod()" 函数，该函数会将函数包装成新类型的
方法。你的代码会像这样:

   class C:
      def meth (cls):
          ...

      meth = classmethod(meth)   # Rebind name to wrapped-up class method

如果方法非常长，很容易错过或忘记在函数体后调用 "classmethod()"。

初衷一直是添加一些语法来使这样的定义更易读，但在 2.2 发布时，一个好的
语法并不明显。今天，一个好的语法 *仍然* 不明显，但用户希望更方便地访问
这个特性；为了满足这一需求，添加了一个新的语法特性。

这个新特性被称为“函数装饰器”。这个名字源于 "classmethod()"、
"staticmethod()" 及其同类函数在函数对象上存储额外信息的想法；它们在用
更多细节 *装饰* 函数。

这种表示法借鉴了 Java，并使用 "'@'" 字符作为指示符。使用新语法，上面的
例子会写成:

   class C:

      @classmethod
      def meth (cls):
          ...

"@classmethod" 是 "meth=classmethod(meth)" 赋值的简写。更一般地，如果
你有以下代码：

   @A
   @B
   @C
   def f ():
       ...

它等价于以下无装饰器的代码:

   def f(): ...
   f = A(B(C(f)))

装饰器必须放在函数定义的前一行，每行一个装饰器，不能与 def 语句在同一
行，这意味着 "@A def f(): ..." 是非法的。你只能装饰模块级别或类内部的
函数定义；不能装饰类定义。

装饰器只是一个函数，它接受要装饰的函数作为参数，并返回相同的函数或某个
新对象。装饰器的返回值不一定是可调用的（尽管通常是这样），除非将进一步
应用装饰器到结果上。编写自己的装饰器很容易。以下简单示例只是在函数对象
上设置一个属性：

   >>> def deco(func):
   ...    func.attr = 'decorated'
   ...    return func
   ...
   >>> @deco
   ... def f(): pass
   ...
   >>> f
   <function f at 0x402ef0d4>
   >>> f.attr
   'decorated'
   >>>

作为一个稍微更现实的例子，以下装饰器检查提供的参数是否为整数：

   def require_int (func):
       def wrapper (arg):
           assert isinstance(arg, int)
           return func(arg)

       return wrapper

   @require_int
   def p1 (arg):
       print arg

   @require_int
   def p2(arg):
       print arg*2

在 **PEP 318** 中的一个示例包含了一个更复杂的版本，它允许你同时指定所
需类型并检查返回类型。

装饰器函数可以接受参数。如果提供了参数，你的装饰器函数仅用这些参数调用
，并且必须返回一个新的装饰器函数；这个函数必须接受单个函数并返回一个函
数，如前所述。换句话说，"@A @B @C(args)" 变为：

   def f(): ...
   _deco = C(args)
   f = A(B(_deco(f)))

理解这一点可能有点费脑筋，但并不太困难。

A small related change makes the "func_name" attribute of functions
writable.  This attribute is used to display function names in
tracebacks, so decorators should change the name of any new function
that's constructed and returned.

参见:

  **PEP 318** - 函数、方法和类的装饰器
     由 Kevin D. Smith、Jim Jewett 和 Skip Montanaro 编写。有几个人编
     写了实现函数装饰器的补丁，但实际被合并的是补丁 #979728，由 Mark
     Russell 编写。

  https://wiki.python.org/moin/PythonDecoratorLibrary
     该Wiki页面包含几个装饰器示例。


PEP 322: 反向迭代
=================

一个新的内置函数 "reversed(seq)"，接受一个序列并返回一个以相反顺序遍历
序列元素的迭代器。

   >>> for i in reversed(xrange(1,4)):
   ...    print i
   ...
   3
   2
   1

与扩展切片（如 "range(1,4)[::-1]"）相比，"reversed()" 更易读，运行更快
，且显著减少内存使用。

请注意，"reversed()" 只接受序列，不接受任意迭代器。如果你想反转一个迭
代器，首先使用 "list()" 将其转换为列表。

   >>> input = open('/etc/passwd', 'r')
   >>> for line in reversed(list(input)):
   ...   print line
   ...
   root:*:0:0:System Administrator:/var/root:/bin/tcsh
     ...

参见:

  **PEP 322** - 反向迭代
     由 Raymond Hettinger 撰写并实现。


PEP 324: 新的子进程模块
=======================

The standard library provides a number of ways to execute a
subprocess, offering different features and different levels of
complexity. "os.system(command)" is easy to use, but slow (it runs a
shell process which executes the command) and dangerous (you have to
be careful about escaping the shell's metacharacters).  The "popen2"
module offers classes that can capture standard output and standard
error from the subprocess, but the naming is confusing.  The
"subprocess" module cleans  this up, providing a unified interface
that offers all the features you might need.

Instead of "popen2"'s collection of classes, "subprocess" contains a
single class called "Popen"  whose constructor supports a number of
different keyword arguments.

   class Popen(args, bufsize=0, executable=None,
               stdin=None, stdout=None, stderr=None,
               preexec_fn=None, close_fds=False, shell=False,
               cwd=None, env=None, universal_newlines=False,
               startupinfo=None, creationflags=0):

*args* 通常是一个字符串序列，用作子进程要执行的程序的参数。 (如果
*shell* 参数为真，*args* 可以是一个字符串，然后会传递给 shell 进行解释
，就像 "os.system()" 所做的那样。)

*stdin*、*stdout* 和 *stderr* 指定子进程的输入、输出和错误流将会是什么
。 你可以提供一个文件对象或文件描述符，或者你可以使用常量
"subprocess.PIPE" 来在子进程和父进程之间创建一个管道。

此构造器有几个方便的选项:

* *close_fds* 将在运行子进程之前请求关闭所有文件描述符。

* *cwd* 指定执行子进程将使用的工作目录（默认为父进程的工作目录）。

* *env* 是一个指定环境变量的字典。

* *preexec_fn* 是将在子进程启动之前被调用的函数。

* *universal_newlines* 使用 Python 的 *universal newlines* 特性打开子
  进程的输入和输出。

一旦你创建了 "Popen" 实例，你可以调用它的 "wait()" 方法来暂停直到子进
程退出，"poll()" 来检查它是否已退出而不暂停，或者 "communicate(data)"
来将字符串 *data* 发送到子进程的标准输入。 "communicate(data)" 然后读
取子进程发送到其标准输出或标准错误的任何数据，返回一个元组
"(stdout_data, stderr_data)"。

"call()" 是一个快捷方式，它将其参数传递给 "Popen" 构造函数，等待命令完
成，并返回子进程的状态码。 它可以作为 "os.system()" 的更安全替代:

   sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb'])
   if sts == 0:
       # Success
       ...
   else:
       # dpkg returned an error
       ...

命令在不使用 shell 的情况下被调用。 如果你确实想使用 shell，你可以添加
"shell=True" 作为关键字参数，并提供一个字符串而不是序列:

   sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True)

PEP 提供了各种 shell 和 Python 代码示例，并展示了它们如何被翻译成使用
"subprocess" 的 Python 代码。强烈建议阅读 PEP 的这一部分。

参见:

  **PEP 324** - 子进程 - 新的进程模块
     由 Peter Åstrand 在 Fredrik Lundh 等人的协助下撰写并实现。


PEP 327: 十进制数据类型
=======================

Python 一直支持基于底层 C 语言 "double" 类型的浮点数（FP）作为数据类型
。然而，尽管大多数编程语言提供了浮点数类型，但许多人（甚至程序员）并不
知道浮点数不能准确表示某些十进制分数。新的 "Decimal" 类型可以准确表示
这些分数，直至用户指定的精度限制。


为什么需要十进制？
------------------

这些限制源于浮点数的表示方式。FP 数由三个部分组成：

* 符号，可以是正或负。

* 尾数，是一个单数字的二进制数后跟一个小数部分。例如，二进制表示的
  "1.01" 是 "1 + 0/2 + 1/4"，即十进制表示的 1.25。

* 指数，指示数字表示中十进制点的位置。

例如，数字 1.25 具有正符号，尾数值为 1.01（二进制），指数为 0（十进制
点不需要移动）。数字 5 具有相同的符号和尾数，但指数为 2，因为尾数乘以
4（2 的指数 2 次方）；1.25 * 4 等于 5。

现代系统通常提供符合IEEE 754标准的浮点支持。C语言的 "double" 类型通常
被实现为64位的IEEE 754数字，其中使用52位空间来存储尾数。这意味着数字只
能精确到52位。如果你试图表示那些展开后会无限重复的数字，其展开会在52位
后截断。不幸的是，大多数软件需要以十进制输出，而十进制中的常见分数在二
进制中往往是无限循环小数。例如，十进制的1.1在二进制中是
``1.0001100110011 ...``；0.1 = 1/16 + 1/32 + 1/256加上无限多个额外项。
IEEE 754必须在52位后截断这个无限重复的小数，因此表示略有误差。

有时在打印数字时可以看到这种不准确性：

   >>> 1.1
   1.1000000000000001

这种不准确性在打印数字时不总是可见，因为浮点数到十进制字符串的转换由C
库提供，大多数C库会尝试生成合理的输出。即使没有显示出来，不准确性仍然
存在，后续操作可能会放大这个误差。

对于许多应用来说，这并不重要。如果我在绘制点并在显示器上显示它们，1.1
和1.1000000000000001之间的差异太小，无法察觉。报告通常限制输出到一定的
小数位数，如果你将数字四舍五入到两位、三位甚至八位小数，误差永远不会显
现。然而，对于确实重要的应用，实现自己的自定义算术例程是一项大量工作。

因此，创建了 "Decimal" 类型。


"Decimal" 类型
--------------

Python标准库中添加了一个新模块 "decimal" 。它包含两个类，"Decimal" 和
"Context"。"Decimal" 实例表示数字，而 "Context" 实例用于封装各种设置，
例如精度和默认舍入模式。

"Decimal" 实例是不可变的，就像常规的 Python 整数和浮点数一样；一旦创建
，就无法更改实例所表示的值。"Decimal" 实例可以从整数或字符串创建：

   >>> import decimal
   >>> decimal.Decimal(1972)
   Decimal("1972")
   >>> decimal.Decimal("1.1")
   Decimal("1.1")

你也可以提供包含符号、以十进制数字元组表示的尾数和指数的元组：

   >>> decimal.Decimal((1, (1, 4, 7, 5), -2))
   Decimal("-14.75")

注意事项：符号位是一个布尔值，所以 0 表示正数，1 表示负数。

从浮点数转换会带来一些问题：表示 1.1 的浮点数应该转换为精确的 1.1 的十
进制数，还是 1.1 加上引入的任何不准确度？决定是回避这个问题，不将此类
转换包含在 API 中。相反，你应该将浮点数转换为字符串，使用所需的精度，
并将字符串传递给 "Decimal" 构造函数：

   >>> f = 1.1
   >>> decimal.Decimal(str(f))
   Decimal("1.1")
   >>> decimal.Decimal('%.12f' % f)
   Decimal("1.100000000000")

一旦你有了 "Decimal" 实例，你可以在它们上执行常规的数学运算。一个限制
：指数运算需要整数指数：

   >>> a = decimal.Decimal('35.72')
   >>> b = decimal.Decimal('1.73')
   >>> a+b
   Decimal("37.45")
   >>> a-b
   Decimal("33.99")
   >>> a*b
   Decimal("61.7956")
   >>> a/b
   Decimal("20.64739884393063583815028902")
   >>> a ** 2
   Decimal("1275.9184")
   >>> a**b
   Traceback (most recent call last):
     ...
   decimal.InvalidOperation: x ** (non-integer)

你可以将 "Decimal" 实例与整数组合，但不能与浮点数组合：

   >>> a + 4
   Decimal("39.72")
   >>> a + 4.5
   Traceback (most recent call last):
     ...
   TypeError: You can interact Decimal only with int, long or Decimal data types.
   >>>

"Decimal" 数字可以与 "math" 和 "cmath" 模块一起使用，但请注意，在进行
操作之前，它们会立即转换为浮点数，这可能导致精度和准确性的损失。你也会
得到一个普通的浮点数，而不是 "Decimal"。

   >>> import math, cmath
   >>> d = decimal.Decimal('123456789012.345')
   >>> math.sqrt(d)
   351364.18288201344
   >>> cmath.sqrt(-d)
   351364.18288201344j

"Decimal" 实例有一个 "sqrt()" 方法，返回一个 "Decimal"，但如果你需要其
他函数，比如三角函数，你将不得不自己实现它们。

   >>> d.sqrt()
   Decimal("351364.1828820134592177245001")


"Context" 类型
--------------

"Context" 类的实例封装了小数操作的几种设置：

* "prec" 是精度，即小数点后的位数。

* "rounding" 指定舍入模式。"decimal" 模块为各种可能性提供了常量：
  "ROUND_DOWN"、"ROUND_CEILING"、"ROUND_HALF_EVEN" 以及其他几种。

* "traps" 是一个字典，指定在遇到某些错误条件时会发生什么：要么抛出异常
  ，要么返回一个值。一些错误条件的例子包括除以零、精度损失和溢出。

通过调用 "getcontext()" 可以获得线程本地的默认上下文；你可以更改此上下
文的属性来改变默认的精度、舍入或错误处理。以下示例显示了更改默认上下文
精度的效果:

   >>> decimal.getcontext().prec
   28
   >>> decimal.Decimal(1) / decimal.Decimal(7)
   Decimal("0.1428571428571428571428571429")
   >>> decimal.getcontext().prec = 9
   >>> decimal.Decimal(1) / decimal.Decimal(7)
   Decimal("0.142857143")

错误条件的默认行为是可选择的；模块可以返回特殊值，如无穷大或非数字，或
者可以抛出异常:

   >>> decimal.Decimal(1) / decimal.Decimal(0)
   Traceback (most recent call last):
     ...
   decimal.DivisionByZero: x / 0
   >>> decimal.getcontext().traps[decimal.DivisionByZero] = False
   >>> decimal.Decimal(1) / decimal.Decimal(0)
   Decimal("Infinity")
   >>>

"Context" 实例还包含多种用于格式化数字的方法，例如 "to_eng_string()"
和 "to_sci_string()"。

更多信息请参阅 "decimal" 模块的文档，其中包含快速入门教程和参考手册。

参见:

  **PEP 327** - 十进数据类型
     由 Facundo Batista 撰写，由Facundo Batista, Eric Price, Raymond
     Hettinger, Aahz 和 Tim Peters 实现。

  http://www.lahey.com/float.htm
     该文章使用 Fortran 代码演示了浮点精度问题可能导致的许多问题。

  http://speleotrove.com/decimal/
     描述了一种基于十进制的表示法。这种表示法已被提议作为标准，并且是
     新的 Python decimal 类型的基础。大部分内容由 Rexx 语言的设计者
     Mike Cowlishaw 撰写。


PEP 328: 多行导入
=================

一个语言改动是针对从模块中导入多个名称的小语法调整。在 "from module
import names" 语句中，*names* 是由逗号分隔的名称序列。如果序列非常长，
您可以要么从同一模块多次导入，要么使用反斜杠转义行尾，如下所示:

   from SimpleXMLRPCServer import SimpleXMLRPCServer,\
               SimpleXMLRPCRequestHandler,\
               CGIXMLRPCRequestHandler,\
               resolve_dotted_attribute

Python 2.4 中的语法改动允许将名称放在括号内。Python 忽略括号表达式中的
换行符，因此不再需要反斜杠:

   from SimpleXMLRPCServer import (SimpleXMLRPCServer,
                                   SimpleXMLRPCRequestHandler,
                                   CGIXMLRPCRequestHandler,
                                   resolve_dotted_attribute)

PEP还提议所有 "import" 语句应为绝对导入，使用前导的 "." 字符表示相对导
入。这部分PEP在Python 2.4中未实现，但在Python 2.5中完成了。

参见:

  **PEP 328** - 导入：多行和绝对/相对导入
     由 Aahz 撰写，多行导入由 Dima Dorfman 实现。


PEP 331: 与区域设置无关的浮点数/字符串转换
==========================================

"locale" 模块让Python软件选择针对特定国家或语言的多种转换和显示约定。
然而，该模块小心翼翼地不更改数字区域设置，因为Python实现中的各种函数要
求数字区域设置保持为 "'C'" 区域。这通常是因为代码使用了C库的 "atof()"
函数。

不设置数字区域设置给使用第三方C库的扩展带来了麻烦，因为它们不会有正确
的区域设置。动机示例是GTK+，其用户界面小部件未在当前区域显示数字。

PEP中描述的解决方案是在Python API中添加三个新函数，执行仅ASCII的转换，
忽略区域设置：

* "PyOS_ascii_strtod(str, ptr)" 和 "PyOS_ascii_atof(str, ptr)" 都将字
  符串转换为C "double"。

* "PyOS_ascii_formatd(buffer, buf_len, format, d)" 将 "double" 转换为
  ASCII字符串。

The code for these functions came from the GLib library
(https://developer.gnome.org/glib/stable/), whose developers kindly
relicensed the relevant functions and donated them to the Python
Software Foundation.  The "locale" module  can now change the numeric
locale, letting extensions such as GTK+  produce the correct results.

参见:

  **PEP 331** - 与区域设置无关的浮点数/字符串转换
     由Christian R. Reis撰写，由 Gustavo Carneiro 实现。


其他语言特性修改
================

以下是 Python 2.4 针对核心 Python 语言的所有改变。

* 增加了用于函数和方法的装饰器 (**PEP 318**)。

* 内置的 "set()" 和 "frozenset()" 类型被添加（**PEP 218**）。其他新内
  置函数包括 "reversed(seq)" 函数（**PEP 322**）。

* 增加了生成器表达式 (**PEP 289**)。

* 某些数值表达式不再返回限于32位或64位的结果 (**PEP 237**)。

* 现在可以在 *from module import names* 语句中的名称列表周围加上括号
  (**PEP 328**)。

* "dict.update()" 方法现在接受与 "dict" 构造函数相同的参数形式。这包括
  任何映射、任何键/值对的迭代器以及关键字参数。（由 Raymond Hettinger
  贡献。）

* 字符串方法 "ljust()"、"rjust()" 和 "center()" 现在接受一个可选参数，
  用于指定除空格以外的填充字符。（由 Raymond Hettinger 贡献。）

* 字符串还增加了一个 "rsplit()" 方法，其工作方式类似于 "split()" 方法
  ，但从字符串末尾开始分割。（由 Sean Reifschneider 贡献。）

     >>> 'www.python.org'.split('.', 1)
     ['www', 'python.org']
     'www.python.org'.rsplit('.', 1)
     ['www.python', 'org']

* 列表的 "sort()" 方法增加了三个关键字参数：*cmp*、*key* 和 *reverse*
  。这些参数使一些常见的 "sort()" 用法变得更简单。所有这些参数都是可选
  的。

  对于 *cmp* 参数，其值应为一个比较函数，该函数接受两个参数，根据参数
  的比较结果返回 -1、0 或 +1。然后使用此函数对列表进行排序。以前这是唯
  一可以提供给 "sort()" 的参数。

  *key* 应该是一个单参数函数，该函数接受一个列表元素并返回该元素的比较
  键。然后使用比较键对列表进行排序。以下示例按不区分大小写的方式对列表
  进行排序:

     >>> 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']

  最后一个示例使用了 *cmp* 参数，这是旧方法来进行不区分大小写的排序。
  它可以工作，但比使用 *key* 参数慢。使用 *key* 参数会对列表中的每个元
  素调用一次 "lower()" 方法，而使用 *cmp* 参数则会在每次比较时调用两次
  ，因此使用 *key* 参数可以减少对 "lower()" 方法的调用。

  对于简单的键函数和比较函数，通常可以通过使用未绑定方法来避免使用
  "lambda" 表达式。例如，上述不区分大小写的排序最好写成：

     >>> L.sort(key=str.lower)
     >>> L
     ['A', 'b', 'c', 'D']

  最后，*reverse* 参数接受一个布尔值。如果值为真，列表将按逆序排序。现
  在你可以用 "L.sort(reverse=True)" 替代 "L.sort(); L.reverse()"。

  排序结果现在保证是稳定的。这意味着具有相同键的两个条目将按照它们输入
  的顺序返回。例如，你可以先按名字对人员列表进行排序，然后再按年龄排序
  ，结果是一个按年龄排序的列表，其中同年龄的人员按名字排序。

  （所有对 "sort()" 方法的更改由 Raymond Hettinger 贡献。）

* 有一个新的内置函数 "sorted(iterable)"，它类似于原地 "list.sort()" 方
  法，但可以在表达式中使用。区别在于：

* 输入可以是任意可迭代对象;

* 新生成的副本被排序，原始列表保持不变；以及

* 表达式返回新的已排序副本

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

  （由 Raymond Hettinger 贡献。）

* 整数运算将不再触发 "OverflowWarning"。"OverflowWarning" 警告将在
  Python 2.5 中消失。

* 解释器新增了一个开关 "-m"，它接受一个名称，在 "sys.path" 上搜索相应
  的模块，并将该模块作为脚本运行。例如，你现在可以使用 "python -m
  profile" 运行 Python 分析器。（由 Nick Coghlan 贡献。）

* "eval(expr, globals, locals)" 和 "execfile(filename, globals,
  locals)" 函数以及 "exec" 语句现在接受任何映射类型作为 *locals* 参数
  。以前这必须是一个普通的 Python 字典。（由 Raymond Hettinger 贡献。
  ）

* "zip()" 内置函数和 "itertools.izip()" 现在在无参数调用时返回一个空列
  表。以前它们会引发 "TypeError" 异常。这使得它们更适合用于可变长度参
  数列表:

     >>> def transpose(array):
     ...    return zip(*array)
     ...
     >>> transpose([(1,2,3), (4,5,6)])
     [(1, 4), (2, 5), (3, 6)]
     >>> transpose([])
     []

  （由 Raymond Hettinger 贡献。）

* 在导入模块时遇到失败将不再在 "sys.modules" 中留下部分初始化的模块对
  象。留下的不完整模块对象会导致后续导入同一模块时误以为成功，进而引发
  混淆的错误。（由 Tim Peters 修复。）

* "None" 现在是一个常量；将一个新值绑定到名称 "None" 的代码现在会造成
  语法错误。 （由 Raymond Hettinger 贡献。）


性能优化
--------

* 列表和元组切片的内部循环经过优化，现在运行速度大约提高了三分之一。字
  典的内部循环也进行了优化，使得 "keys()"、"values()"、"items()"、
  "iterkeys()"、"itervalues()" 和 "iteritems()" 的性能得到提升。（由
  Raymond Hettinger 贡献。）

* 用于列表增长和缩小的机制进行了速度和空间效率的优化。由于更高效的代码
  路径和更少地使用底层系统 "realloc()"，向列表追加和弹出元素现在运行得
  更快。列表推导也从中受益。"list.extend()" 也进行了优化，不再将其参数
  转换为临时列表后再扩展基础列表。（由 Raymond Hettinger 贡献。）

* "list()"、"tuple()"、"map()"、"filter()" 和 "zip()" 在使用提供
  "__len__()" 方法的非序列参数时，现在运行速度提高了数倍。（由 Raymond
  Hettinger 贡献。）

* "list.__getitem__()"、"dict.__getitem__()" 和 "dict.__contains__()"
  方法现在实现为 "method_descriptor" 对象，而不是 "wrapper_descriptor"
  对象。这种访问形式使它们的性能翻倍，更适合作为函数式编程的参数使用：
  "map(mydict.__getitem__, keylist)"。（由 Raymond Hettinger 贡献。）

* 添加了一个新的操作码 "LIST_APPEND"，简化了列表推导生成的字节码，并使
  其速度提高了大约三分之一。（由 Raymond Hettinger 贡献。）

* 窥孔字节码优化器得到了改进，能够生成更短、更快的字节码；值得注意的是
  ，生成的字节码更易读。（由 Raymond Hettinger 增强。）

* 在形式为 "s = s + "abc"" 和 "s += "abc"" 的语句中，字符串连接现在在
  某些情况下会更高效地执行。这种优化不会出现在其他Python实现中，例如
  Jython，因此你不应依赖它；当你需要高效地连接大量字符串时，仍然推荐使
  用字符串的 "join()" 方法。（由Armin Rigo贡献。）

2.4版本优化的净结果是，Python 2.4运行pystone基准测试比Python 2.3快约5%
，比Python 2.2快35%。（pystone并不是一个特别好的基准测试，但它是衡量
Python性能最常用的方法。你的应用程序可能从Python 2.4中获得更大或更小的
收益。）


新增，改进和弃用的模块
======================

一如既往，Python的标准库获得了一些增强和错误修复。以下是一些最显著变化
的部分列表，按模块名称字母顺序排序。请查阅源树中的 "Misc/NEWS" 文件以
获取更完整的变化列表，或通过CVS日志查看所有细节。

* The "asyncore" module's "loop()" function now has a *count*
  parameter that lets you perform a limited number of passes through
  the polling loop.  The default is still to loop forever.

* "base64" 模块现在更完整地支持 **RFC 3548** 中的Base64、Base32和
  Base16编码和解码，包括可选的大小写折叠和可选的替代字母表。（由Barry
  Warsaw贡献。）

* "bisect" 模块现在有底层的C实现，以提升性能。（由Dmitry Vasiliev贡献
  。）

* 由 Hye-Shik Chang 维护的东亚编解码器的 CJKCodecs 集合已集成到 2.4 中
  。新的编码为：

* 汉语（大陆）: gb2312, gbk, gb18030, big5hkscs, hz

* 汉语（台湾）: big5, cp950

* 日语: cp932, euc-jis-2004, euc-jp, euc-jisx0213, iso-2022-jp,
     iso-2022-jp-1, iso-2022-jp-2, iso-2022-jp-3, iso-2022-jp-ext,
     iso-2022-jp-2004, shift-jis, shift-jisx0213, shift-jis-2004

* 韩语: cp949, euc-kr, johab, iso-2022-kr

* 添加了其他一些新的编码：HP Roman8, ISO_8859-11, ISO_8859-16,
  PCTP-154 和 TIS-620

* UTF-8和UTF-16编解码器现在更好地处理接收部分输入的情况。以前，
  "StreamReader" 类会尝试读取更多数据，使得无法从流中恢复解码。
  "read()" 方法现在将返回尽可能多的数据，后续调用将从之前停止的地方恢
  复解码。（由Walter Dörwald实现。）

* 有一个新的 "collections" 模块，用于各种专业化的集合数据类型。目前它
  只包含一种类型，"deque"，这是一个双端队列，支持高效地从两端添加和移
  除元素:

     >>> from collections import deque
     >>> d = deque('ghi')        # make a new deque with three items
     >>> d.append('j')           # add a new entry to the right side
     >>> d.appendleft('f')       # add a new entry to the left side
     >>> d                       # show the representation of the deque
     deque(['f', 'g', 'h', 'i', 'j'])
     >>> d.pop()                 # return and remove the rightmost item
     'j'
     >>> d.popleft()             # return and remove the leftmost item
     'f'
     >>> list(d)                 # list the contents of the deque
     ['g', 'h', 'i']
     >>> 'h' in d                # search the deque
     True

  多个模块，如 "Queue" 和 "threading" 模块，现在利用
  "collections.deque" 来提高性能。（由 Raymond Hettinger 贡献。）

* The "ConfigParser" classes have been enhanced slightly. The "read()"
  method now returns a list of the files that were successfully
  parsed, and the "set()" method raises "TypeError" if passed a
  *value* argument that isn't a string.   (Contributed by John
  Belmonte and David Goodger.)

* "curses" 模块现在支持 ncurses 扩展 "use_default_colors()"。在终端支
  持透明度的平台上，这使得使用透明背景成为可能。（由 Jörg Lehmann 贡献
  。）

* "difflib" 模块现在包含一个 "HtmlDiff" 类，该类创建一个 HTML 表格，显
  示两个文本版本的并列比较。（由 Dan Gass 贡献。）

* "email" 包已更新至 3.0 版本，该版本移除了多种已弃用的 API，并取消了
  对于 Python 2.3 之前版本的支持。3.0 版本的包使用了一个新的增量解析器
  来处理 MIME 消息，该解析器位于 "email.FeedParser" 模块中。新解析器不
  需要将整个消息读入内存，且在消息格式不正确时不会抛出异常；相反，它会
  将任何问题记录在消息的 "defect" 属性中。（由 Anthony Baxter、Barry
  Warsaw、Thomas Wouters 等人开发。）

* "heapq" 模块已被转换为 C 语言实现。由此带来的速度提升达十倍，使得该
  模块适合处理大量数据。此外，该模块新增了两个函数 "nlargest()" 和
  "nsmallest()"，它们使用堆来查找数据集中的 N 个最大或最小值，而无需进
  行完整的排序。（由 Raymond Hettinger 贡献。）

* The "httplib" module now contains constants for HTTP status codes
  defined in various HTTP-related RFC documents.  Constants have names
  such as "OK", "CREATED", "CONTINUE", and "MOVED_PERMANENTLY"; use
  pydoc to get a full list.  (Contributed by Andrew Eland.)

* "imaplib" 模块现在支持 IMAP 的 THREAD 命令（由 Yves Dionne 贡献）以
  及新的 "deleteacl()" 和 "myrights()" 方法（由 Arnaud Mazin 贡献）。

* "itertools" 模块新增了 "groupby(iterable[, *func*])" 函数。
  *iterable* 是可以迭代以返回元素流的对象，可选的 *func* 参数是一个函
  数，它接受一个元素并返回一个键值；如果省略，键即为元素本身。
  "groupby()" 然后将元素分组为具有匹配键值的子序列，并返回一系列包含键
  值和子序列迭代器的 2 元组。

  以下是一个示例，以便更清晰地说明这一点。*key* 函数 simply 返回一个数
  字是奇数还是偶数，因此 "groupby()" 的结果就是返回连续的奇数或偶数序
  列。:

     >>> import itertools
     >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14]
     >>> for key_val, it in itertools.groupby(L, lambda x: x % 2):
     ...    print key_val, list(it)
     ...
     0 [2, 4, 6]
     1 [7]
     0 [8]
     1 [9, 11]
     0 [12, 14]
     >>>

  "groupby()" 通常用于处理已排序的输入。"groupby()" 的逻辑类似于 Unix
  的 "uniq" 过滤器，这使得它非常适合用于消除、计数或识别重复元素:

     >>> word = 'abracadabra'
     >>> letters = sorted(word)   # Turn string into a sorted list of letters
     >>> letters
     ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
     >>> for k, g in itertools.groupby(letters):
     ...    print k, list(g)
     ...
     a ['a', 'a', 'a', 'a', 'a']
     b ['b', 'b']
     c ['c']
     d ['d']
     r ['r', 'r']
     >>> # List unique letters
     >>> [k for k, g in groupby(letters)]
     ['a', 'b', 'c', 'd', 'r']
     >>> # Count letter occurrences
     >>> [(k, len(list(g))) for k, g in groupby(letters)]
     [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]

  （由 Hye-Shik Chang 贡献。）

* "itertools" 还增加了一个名为 "tee(iterator, N)" 的函数，它返回 *N*
  个独立迭代器，这些迭代器复制 *iterator*。如果省略 *N*，默认值为 2。:

     >>> L = [1,2,3]
     >>> i1, i2 = itertools.tee(L)
     >>> i1,i2
     (<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>)
     >>> list(i1)               # Run the first iterator to exhaustion
     [1, 2, 3]
     >>> list(i2)               # Run the second iterator to exhaustion
     [1, 2, 3]

  请注意，"tee()" 需要保留由迭代器返回的值的副本；在最坏的情况下，它可
  能需要保留所有这些值。因此，如果领先迭代器在长输入流中远远领先于滞后
  迭代器，应谨慎使用此功能。如果分离较大，那么您可能还不如使用
  "list()"。当迭代器彼此紧密跟踪时，"tee()" 是理想的。可能的用例包括书
  签、窗口化或前瞻迭代器。（由 Raymond Hettinger 贡献。）

* A number of functions were added to the "locale"  module, such as
  "bind_textdomain_codeset()" to specify a particular encoding and a
  family of "l*gettext()" functions that return messages in the chosen
  encoding. (Contributed by Gustavo Niemeyer.)

* "logging" 包的 "basicConfig()" 函数添加了一些关键字参数，以简化日志
  配置。默认行为是将消息记录到标准错误，但可以指定各种关键字参数以将日
  志记录到特定文件、更改日志格式或设置日志级别。例如：

     import logging
     logging.basicConfig(filename='/var/log/application.log',
         level=0,  # Log all messages
         format='%(levelname):%(process):%(thread):%(message)')

  "logging" 包的其他添加内容包括一个 "log(level, msg)" 便捷方法，以及
  一个 "TimedRotatingFileHandler" 类，该类在定时间隔旋转其日志文件。模
  块已经有一个 "RotatingFileHandler"，它在文件超过特定大小时旋转日志。
  这两个类都派生自一个新的 "BaseRotatingHandler" 类，该类可用于实现其
  他旋转处理程序。

  （更改由 Vinay Sajip 实现。）

* "marshal" 模块现在在解包数据结构时共享内部字符串。这可能会缩小某些
  pickle 字符串的大小，但主要效果是使 ".pyc" 文件显著变小。（由 Martin
  von Löwis 贡献。）

* The "nntplib" module's "NNTP" class gained "description()" and
  "descriptions()" methods to retrieve  newsgroup descriptions for a
  single group or for a range of groups. (Contributed by Jürgen A.
  Erhard.)

* "operator" 模块新增了两个函数，"attrgetter(attr)" 和
  "itemgetter(index)"。这两个函数都返回一个接受单个参数并返回相应属性
  或项的可调用对象；这些可调用对象在与 "map()" 或 "sorted()" 一起使用
  时，是非常优秀的数据提取器。例如：

     >>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)]
     >>> map(operator.itemgetter(0), L)
     ['c', 'd', 'a', 'b']
     >>> map(operator.itemgetter(1), L)
     [2, 1, 4, 3]
     >>> sorted(L, key=operator.itemgetter(1)) # Sort list by second tuple item
     [('d', 1), ('c', 2), ('b', 3), ('a', 4)]

  （由 Raymond Hettinger 贡献。）

* "optparse" 模块进行了多项更新。该模块现在通过 "gettext.gettext()" 传
  递其消息，使得可以国际化 Optik 的帮助和错误消息。选项的帮助消息现在
  可以包含字符串 "'%default'"，该字符串将被选项的默认值替换。（由 Greg
  Ward 贡献。）

* The long-term plan is to deprecate the "rfc822" module in some
  future Python release in favor of the "email" package. To this end,
  the "email.Utils.formatdate()" function has been changed to make it
  usable as a replacement for "rfc822.formatdate()".  You may want to
  write new e-mail processing code with this in mind.  (Change
  implemented by Anthony Baxter.)

* "os" 模块新增了 "urandom(n)" 函数，返回一个包含 *n* 字节随机数据的字
  符串。该函数提供了对平台特定随机源（如 Linux 上的 "/dev/urandom" 或
  Windows CryptoAPI）的访问。（由 Trevor Perrin 贡献。）

* 另一个新函数："os.path.lexists(path)" 如果指定的文件存在（无论是否为
  符号链接）则返回 true。这与现有的 "os.path.exists(path)" 函数不同，
  后者在 *path* 是指向不存在目标的符号链接时返回 false。（由 Beni
  Cherniavsky 贡献。）

* 在 "os" 之下 "posix" 模块中新增了一个 "getsid()" 函数。 （由 J.
  Raynor 贡献。）

* "poplib" 模块现在已支持 SSL 上的 POP。 （由 Hector Urtubia 贡献。）

* 现在 "profile" 模块将可对 C 扩展函数执行性能分析。 （由 Nick Bastin
  贡献。）

* "random" 模块有一个新方法 "getrandbits(N)"，返回一个长度为 *N* 位的
  长整数。现有的 "randrange()" 方法现在在适当的情况下使用
  "getrandbits()"，使得生成任意大的随机数更加高效。（由 Raymond
  Hettinger 贡献。）

* "re" 模块接受的正则表达式语言扩展了简单的条件表达式，写作
  "(?(group)A|B)"。*group* 可以是数字组 ID 或用 "(?P<group>...)" 在表
  达式中提前定义的组名。如果指定的组匹配，正则表达式模式 *A* 将被用于
  测试字符串；如果组未匹配，则使用模式 *B*。（由 Gustavo Niemeyer 贡献
  。）

* 由于 Gustavo Niemeyer 大量工作，"re" 模块也不再是递归的。在递归正则
  表达式引擎中，某些模式会导致大量 C 栈空间被消耗，甚至可能溢出栈。例
  如，如果你将一个 30000 字节的 "a" 字符串与表达式 "(a|b)+" 匹配，每个
  字符会消耗一个栈帧。Python 2.3 试图检查栈溢出并抛出 "RuntimeError"
  异常，但某些模式可以绕过检查，如果你运气不好，Python 可能会段错误。
  Python 2.4 的正则表达式引擎可以无问题地匹配此模式。

* "signal" 模块现在对 "signal.signal()" 函数的参数进行更严格的错误检查
  。例如，你不能在 "SIGKILL" 信号上设置处理程序；之前的 Python 版本会
  默默接受这一点，但 2.4 版本将引发一个 "RuntimeError" 异常。

* "socket" 模块新增了两个函数。"socketpair()" 返回一对已连接的套接字，
  而 "getservbyport(port)" 用于查找给定端口号的服务名称。（由 Dave
  Cole 和 Barry Warsaw 贡献。）

* "sys.exitfunc()" 函数已被弃用。代码应使用现有的 "atexit" 模块，它能
  正确处理调用多个退出函数。最终 "sys.exitfunc()" 将成为一个纯内部接口
  ，仅由 "atexit" 访问。

* 现在 "tarfile" 模块默认将生成 GNU 格式的 tar 文件。 （由 Lars
  Gustäbel 贡献。）

* "threading" 模块现在有了一种优雅简洁的方式来支持线程本地数据。该模块
  包含一个 "local" 类，其属性值对不同线程是本地的。:

     import threading

     data = threading.local()
     data.number = 42
     data.url = ('www.python.org', 80)

  其他线程可以为 "number" 和 "url" 属性分配和检索它们自己的值。你可以
  子类化 "local" 来初始化属性或添加方法。（由 Jim Fulton 贡献。）

* "timeit" 模块现在在计时循环中自动禁用周期性垃圾收集。这一改变使得连
  续计时更具可比性。（由 Raymond Hettinger 贡献。）

* "weakref" 模块现在支持更多种类的对象，包括 Python 函数、类实例、集合
  、冻结集合、双端队列、数组、文件、套接字和正则表达式模式对象。（由
  Raymond Hettinger 贡献。）

* The "xmlrpclib" module now supports a multi-call extension for
  transmitting multiple XML-RPC calls in a single HTTP operation.
  (Contributed by Brian Quinlan.)

* "mpz", "rotor" 和 "xreadlines" 模块已被移除。


cookielib
---------

The "cookielib" library supports client-side handling for HTTP
cookies, mirroring the "Cookie" module's server-side cookie support.
Cookies are stored in cookie jars; the library transparently stores
cookies offered by the web server in the cookie jar, and fetches the
cookie from the jar when connecting to the server. As in web browsers,
policy objects control whether cookies are accepted or not.

为了跨会话存储 Cookie，提供了两种 Cookie 罐的实现：一种以 Netscape 格
式存储 Cookie，以便应用程序可以使用 Mozilla 或 Lynx 的 Cookie 文件，另
一种以与 Perl libwww 库相同的格式存储 Cookie。

"urllib2" has been changed to interact with "cookielib":
"HTTPCookieProcessor" manages a cookie jar that is used when accessing
URLs.

该模块由  John J. Lee 贡献。


doctest
-------

由于 Edward Loper 和 Tim Peters 的贡献，"doctest" 模块进行了大量重构。
测试仍然可以简单到只需运行 "doctest.testmod()"，但重构允许以各种方式自
定义模块的操作。

新的 "DocTestFinder" 类从给定对象的文档字符串中提取测试：

   def f (x, y):
       """>>> f(2,2)
   4
   >>> f(3,2)
   6
       """
       return x*y

   finder = doctest.DocTestFinder()

   # Get list of DocTest instances
   tests = finder.find(f)

新的 "DocTestRunner" 类然后运行单个测试并可以生成结果摘要：

   runner = doctest.DocTestRunner()
   for t in tests:
       tried, failed = runner.run(t)

   runner.summarize(verbose=1)

上述示例生成以下输出：

   1 items passed all tests:
      2 tests in f
   2 tests in 1 items.
   2 passed and 0 failed.
   Test passed.

"DocTestRunner" 使用一个 "OutputChecker" 类的实例来比较预期输出和实际
输出。这个类接受多个不同的标志来定制其行为；有野心的用户也可以编写一个
全新的 "OutputChecker" 子类。

默认的输出检查器提供了一些方便的功能。例如，使用 "doctest.ELLIPSIS" 选
项标志，预期输出中的省略号（"..."）可以匹配任何子字符串，这使得更容易
适应在细小方面有所变化的输出:

   def o (n):
       """>>> o(1)
   <__main__.C instance at 0x...>
   >>>
   """

另一个特殊字符串，"<BLANKLINE>", 匹配一个空行:

   def p (n):
       """>>> p(1)
   <BLANKLINE>
   >>>
   """

另一个新功能是通过指定 "doctest.REPORT_UDIFF" (统一差异) 、
"doctest.REPORT_CDIFF" (上下文差异) 或 "doctest.REPORT_NDIFF" (增量式
差异) 选项标志，生成输出差异风格的显示。例如:

   def g (n):
       """>>> g(4)
   here
   is
   a
   lengthy
   >>>"""
       L = 'here is a rather lengthy list of words'.split()
       for word in L[:n]:
           print word

在指定 "doctest.REPORT_UDIFF" 的情况下运行上述函数的测试，你会得到以下
输出：

   **********************************************************************
   File "t.py", line 15, in g
   Failed example:
       g(4)
   Differences (unified diff with -expected +actual):
       @@ -2,3 +2,3 @@
        is
        a
       -lengthy
       +rather
   **********************************************************************


构建和 C API 的改变
===================

对于 Python 构建过程和 C API 的一些修改:

* 为常见扩展函数返回值添加了三个新的便利宏："Py_RETURN_NONE"、
  "Py_RETURN_TRUE" 和 "Py_RETURN_FALSE"。（由 Brett Cannon 贡献。）

* 另一个新宏，"Py_CLEAR"，减少 *obj* 的引用计数并将 *obj* 设置为空指针
  。（由 Jim Fulton 贡献。)

* 一个新的函数 "PyTuple_Pack(N, obj1, obj2, ..., objN)"，可以从一个可
  变长度的Python对象参数列表中构造元组。（由Raymond Hettinger贡献。）

* 一个新的函数 "PyDict_Contains(d, k)"，实现了快速的字典查找，而不会掩
  盖查找过程中引发的异常。（由Raymond Hettinger贡献。）

* 宏 "Py_IS_NAN(X)" 如果其浮点或双精度参数 *X* 是NaN，则返回1。（由Tim
  Peters贡献。）

* C code can avoid unnecessary locking by using the new
  "PyEval_ThreadsInitialized()" function to tell  if any thread
  operations have been performed.  If this function  returns false, no
  lock operations are needed. (Contributed by Nick Coghlan.)

* 一个新的函数 "PyArg_VaParseTupleAndKeywords()"，与
  "PyArg_ParseTupleAndKeywords()" 相同，但接受一个 "va_list" 而不是参
  数数量。（由Greg Chapman贡献。）

* A new method flag, "METH_COEXISTS", allows a function defined in
  slots to co-exist with a "PyCFunction" having the same name.  This
  can halve the access time for a method such as "set.__contains__()".
  (Contributed by Raymond Hettinger.)

* Python现在可以内置对解释器本身的额外分析功能，旨在帮助开发Python核心
  的人员。向 **configure** 脚本提供 "--enable-profiling" 选项将允许您
  使用 **gprof** 对解释器进行分析，提供 "--with-tsc" 开关则启用使用
  Pentium的时间戳计数器寄存器进行分析。请注意，"--with-tsc" 开关命名略
  有不当，因为该分析功能在PowerPC平台上也能工作，尽管该处理器架构不将
  该寄存器称为“TSC寄存器”。（由Jeremy Hylton贡献。）

* The "tracebackobject" type has been renamed to "PyTracebackObject".


移植专属的改变
--------------

* Windows端口现在可以在MSVC++ 7.1以及版本6下构建。（由Martin von Löwis
  贡献。）


移植到 Python 2.4
=================

本节列出了先前描述的可能需要修改你的代码的改变：

* 左移操作和过大的十六进制/八进制常量不再触发 "FutureWarning"，并且返
  回一个限制在32或64位的值；相反，它们返回一个长整数。

* 整数运算将不再触发 "OverflowWarning"。"OverflowWarning" 警告将在
  Python 2.5 中消失。

* "zip()" 内置函数和 "itertools.izip()" 现在在无参数调用时返回一个空列
  表，而不是抛出 "TypeError" 异常。

* 您不能再比较由 "datetime" 模块提供的 "date" 和 "datetime" 实例。不同
  类的两个实例现在将始终不相等，并且相对比较（"<"，">"）将抛出
  "TypeError"。

* "dircache.listdir()" now passes exceptions to the caller instead of
  returning empty lists.

* "LexicalHandler.startDTD()" 过去接收公共和系统 ID 的顺序错误。这已被
  纠正；依赖错误顺序的应用程序需要修复。

* 现在 "fcntl.ioctl()" 会在 *mutate* 参数被省略并且将造成影响时发出警
  告。

* 现在 "tarfile" 模块默认将生成 GNU 格式的 tar 文件。

* 在导入模块时遭遇失败不会再将部分初始化的模块对象留在 "sys.modules"
  中。

* 现在 "None" 是一个常量；将一个新值绑定到 "None" 将导致语法错误。

* 现在对于某些非法的值 "signals.signal()" 函数将引发 "RuntimeError" 异
  常；在之前版本中这些错误会静默地放过。 例如，你将不能在 "SIGKILL" 信
  号上设置处理器。


致谢
====

作者感谢以下人员对本文各种草稿给予的建议，更正和协助：Koray Can, Hye-
Shik Chang, Michael Dyck, Raymond Hettinger, Brian Hurt, Hamish
Lawson, Fredrik Lundh, Sean Reifschneider, Sadruddin Rejeb.
