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

作者:
   A.M. Kuchling


概述
====

本文介绍了 Python 2.1 的新增特性。 虽然 2.1 的改变没有 Python 2.0 那么
多，但是仍然有一些令人惊喜的东西。 2.1 是第一个使用 Python 增强提议，
即 PEP 来进行引导的发行版，因此大部分重要的改变都有相应的 PEP 来提供有
关改变的更完整文档和设计思路。 本文并未试图完整记录所有的新特性，而是
为 Python 程序员提供新特性的简单概览。 请参阅 Python 2.1 文档，或特定
的 PEP，获取针对你感兴趣的任何新特性的更多细节。

Python 开发团队的一个近期目标是加速新发行版的步调，使得每 6 到 9 个月
就有一个新发行版。 2.1 是基于这个新步调推出的第一个发行版，第一个内测
版将于一月发布，即 2.0 最终版发布 3 个月之后。

Python 2.1 的最终版本于2001年4月17日发布。


PEP 227: 嵌套的作用域
=====================

Python 2.1 中的最大改变是 Python 的作用域规则。 在 Python 2.0 中，任意
给定的时刻至多使用三个命名空间来查找变量名称：局部、模块和内置命名空间
。 这往往会导致令人吃惊的结果因为它与人们直觉上的预期不相匹配。 例如，
一个嵌套的递归函数将不起作用:

   def f():
       ...
       def g(value):
           ...
           return g(value-1) + 1
       ...

函数 "g()" 总是会引发 "NameError" 异常，因为名称 "g" 的绑定既不在局部
命名空间中也不在模块级命名空间中。 这在实践中不会有太大问题（你会经常
这样递归地定义内部函数吗？），但是这也会让 "lambda" 表达式的使用更为笨
拙，这在实践中是有问题的。 在使用了 "lambda" 的代码中你经常能发现局部
变量通过作为参数的默认值被拷贝。

   def find(self, name):
       "Return list of any entries equal to 'name'"
       L = filter(lambda x, name=name: x == name,
                  self.list_attribute)
       return L

结果将会严重损害以高度函数式风格编写的 Python 代码的可读性。

Python 2.1 最显著的改变是增加了静态作用域这一语言特征来解决此问题。 作
为它的第一项影响，在上述示例中的 "name=name" 默认参数现在将不再必要。
简单地说，当一个函数内部的给定变量名没有被赋值时（通过赋值语句，或者
"def", "class" 或 "import" 语句），对该变量的引用将在外层作用域的局部
命名空间中查找。 对于该规则的更详细解释，以及具体实现的分析，请参阅相
应的 PEP。

对于同时在模块层级和包含下层函数定义的函数内部局部变量使用了相同变量名
的代码来说这项改变可能会导致一些兼容性问题。 不过这看来不太可能发生，
因为阅读这样的代码本来就会相当令人困惑。

此项改变的一个附带影响是在特定条件下函数作用域内部 "from module import
*" 和 "exec" 语句将不允许使用。 Python 参考手册已经写明 "from module
import *" 仅在模块最高层级上是可用的，但此前 CPython 解释器从未强制实
施此规则。 作为嵌套作用域具体实现的一部分，将 Python 源码转为字节码的
编译器会生成不同的代码来访问某个包含作用域内的变量。 "from module
import *" 和 "exec" 会使得编译器无法正确执行，因为它们会向局部命名空间
添加在编译时还不存在的名称。 为此，如果一个函数包含带有自由变量的函数
定义或 "lambda" 表达式，编译器将通过引发 "SyntaxError" 异常来提示。

为了使前面的解释更清楚，下面是一个例子:

   x = 1
   def f():
       # 下一行有语法错误
       exec 'x=2'
       def g():
           return x

包含 "exec" 语句的第 4 行有语法错误，因为 "exec" 会定义一个名为 "x" 的
新局部变量，它的值应当被 "g()" 所访问。

这应该不会是太大的限制，因为 "exec" 在多数 Python 代码中都极少被使用（
而当它被使用时，往往也是个存在糟糕设计的信号）。

由于兼容性问题，嵌套作用域被逐步引入；在 Python 2.1 中，它们默认未启用
，但可以通过在模块中使用 future 语句来开启，如 **PEP 236** 所述。 （参
见下一节对 **PEP 236** 的进一步讨论。） 在 Python 2.2 中，嵌套作用域将
成为默认设置，并且无法关闭，但用户将有整个 2.1 版本的生命周期来修复因
引入嵌套作用域而导致的任何问题。

参见:

  **PEP 227** - 静态嵌套作用域
     由 Jeremy Hylton 撰写并实现。


PEP 236: __future__ 指令
========================

对嵌套作用域的反应引起了广泛关注，人们担心在 Python 2.1 版本发布时会破
坏现有代码，强烈的反应促使 Python 开发者采取了更保守的策略。这个策略包
括引入一种约定，在版本 N 中启用可选功能，该功能将在版本 N+1 中成为强制
功能。

语法使用 "from...import" 语句，使用保留模块名 "__future__"。可以通过以
下语句启用嵌套作用域:

   from __future__ import nested_scopes

虽然它看起来像一个普通的 "import" 语句，但实际上并不是；关于此类
future 语句的位置有严格的规定。它们只能放在模块的顶部，必须位于任何
Python 代码或常规 "import" 语句之前。这是因为这样的语句会影响 Python
字节码编译器解析代码和生成字节码的方式，因此它们必须在任何会生成字节码
的语句之前出现。

参见:

  **PEP 236** - 回到 "__future__"
     由 Tim Peters 撰写，主要由 Jeremy Hylton 实现。


PEP 207: 富比较
===============

在早期版本中，Python 对用户定义类和扩展类型的比较操作支持相当简单。类
可以实现一个 "__cmp__()" 方法，该方法接收两个类实例，并且只能返回 0 表
示相等，或 +1 或 -1 表示不相等；该方法不能引发异常或返回布尔值以外的任
何内容。Numeric Python 的用户经常发现这种模型太弱且受限，因为在
Numeric Python 所用的数字运算程序中，能够对两个矩阵进行逐元素比较更为
有用，返回一个包含每个元素比较结果的矩阵。如果两个矩阵的大小不同，则比
较必须能够引发异常以表示错误。

在 Python 2.1 中增加了富比较操作以支持这一需求。 Python 类现在可以单独
重载 "<", "<=", ">", ">=", "==" 和 "!=" 中的每个操作。 新的魔术方法名
称如下：

+-------------+--------------------------+
| 运算        | 方法名称                 |
|=============|==========================|
| "<"         | "__lt__()"               |
+-------------+--------------------------+
| "<="        | "__le__()"               |
+-------------+--------------------------+
| ">"         | "__gt__()"               |
+-------------+--------------------------+
| ">="        | "__ge__()"               |
+-------------+--------------------------+
| "=="        | "__eq__()"               |
+-------------+--------------------------+
| "!="        | "__ne__()"               |
+-------------+--------------------------+

（这些魔术方法是以对应的 Fortran 操作符命名的，如 ".LT."、".LE." 等。
数值程序员几乎肯定对这些名称非常熟悉，并且会发现它们易于记忆。）

每个这样的魔术方法的形式都是 "method(self, other)"，其中 "self" 是操作
符左侧的对象，而 "other" 是操作符右侧的对象。 例如，表达式 "A < B" 会
调用 "A.__lt__(B)"。

这些魔术方法可以返回任何类型的值：布尔值、矩阵、列表或任何其他 Python
对象。或者，如果比较是不可能的、不一致的或没有意义的，它们也可以引发异
常。

内置的 "cmp(A,B)" 函数可以使用富比较机制，现在接受一个可选参数来指定要
使用的比较操作；该参数可以是字符串 ""<""、""<=""、"">""、"">=""、
""=="" 或 ""!="" 之一。 如果不带可选的第三个参数调用，"cmp()" 函数将只
返回 -1、0 或 +1，就像以前的 Python 版本一样；否则，它将调用适当的方法
并可以返回任何 Python 对象。

对于 C 程序员来说，也有相应的变更；类型对象中有一个新的槽位
"tp_richcmp" 以及一个用于执行指定富比较的 API。 这里我不会涉及 C API
的具体内容，完整的相关函数列表请参阅 **PEP 207** 或 2.1 的 C API 文档
。

参见:

  **PEP 207** - 富比较
     由 Guido van Rossum 编写，大量参考 David Ascher 的先期工作，并由
     Guido van Rossum 实现。


PEP 230: 警告框架
=================

在过去的 10 年中，Python 积累了一定数量的过时模块和功能。 由于无法确切
知道某个功能被使用的程度：可能没有程序依赖该功能，也可能有很多程序依赖
，因此很难确定何时可以安全地移除某个功能，为了以更结构化的方式移除旧功
能，添加了一个警告框架。 当 Python 开发者想要废弃某个功能时，它会在下
一个 Python 版本中首先触发一个警告。 然后，在随后的Python版本中可以移
除该功能，这样用户将有一个完整的发布周期来删除对旧功能的使用。

Python 2.1 增加了警告框架以用于此方案。 它增加了一个 "warnings" 模块，
该模块提供了发出警告的函数，以及过滤掉不想显示的警告的功能。 第三方模
块也可以使用这个框架来弃用它们不再希望支持的旧功能。

例如，在 Python 2.1 中，"regex" 模块已被弃用，因此导入它会打印出一个警
告:

   >>> import regex
   __main__:1: DeprecationWarning: the regex module
            is deprecated; please use the re module
   >>>

警告可以通过调用 "warnings.warn()" 函数来发出:

   warnings.warn("feature X no longer supported")

第一个形参是警告消息；额外的可选形参可被用来指定一个专门的警告类别。

可以添加过滤器来禁用特定的警告；可以将某个正则表达式模式应用于消息或模
块名称以抑制警告。 例如，你可能有一个使用 "regex" 模块的程序但现在不想
花时间将其转换为使用 "re" 模块。 可以通过以下调用来抑制警告消息

   import warnings
   warnings.filterwarnings(action = 'ignore',
                           message='.*regex module is deprecated',
                           category=DeprecationWarning,
                           module = '__main__')

这添加了一个过滤器，该过滤器仅适用于在 "__main__" 模块中触发的
"DeprecationWarning" 类警告，并应用一个正则表达式来仅匹配有关 "regex"
模块已被弃用的消息，这将导致忽略此类警告。警告还可以仅打印一次，每次执
行违规代码时打印，或者转换为异常，从而导致程序停止（当然，除非以常规方
式捕获这些异常）。

Python 的 C API 也增加了用于发出警告的函数；详情请参阅 PEP 230 或
Python 的 API 文档。

参见:

  **PEP 5** - 语言演化的准则
     该文档由 Paul Prescod 撰写，旨在规定移除 Python 旧功能时应遵循的
     程序。 尽管本文描述的政策尚未被正式采纳，但最终的政策可能不会与
     Prescod 的提议有太大不同。

  **PEP 230** - 警告框架
     由 Guido van Rossum 撰写并实现。


PEP 229: 新的构建系统
=====================

在编译 Python 时，用户必须进入并编辑 "Modules/Setup" 文件以启用各种附
加模块；默认集相对较小，并且仅限于在大多数 Unix 平台上编译的模块。这意
味着在具有更多功能的 Unix 平台上，特别是 Linux，Python 安装通常不包含
所有可能有用的模块。

Python 2.0 添加了 Distutils，一组用于分发和安装扩展模块的模块。在
Python 2.1 中，Distutils 被用于编译大部分标准库扩展模块，自动检测当前
机器上支持哪些模块。希望这将使 Python 的安装更加容易并具有更多功能。

不再需要编辑 "Modules/Setup" 文件来启用模块，而是在 Python 源代码分发
包的顶层目录运行一个 "setup.py" 脚本，该脚本在构建时尝试通过检查系统上
的模块和头文件来发现可以启用那些模块。 如果某个模块已在
"Modules/Setup" 中配置，则 "setup.py" 脚本不会尝试编译该模块，并会遵从
"Modules/Setup" 文件中的内容。 这提供了一种方式来指定特定平台所需的任
何奇怪的命令行旗标或库。

在对构建机制的另一项重大更改中，Neil Schemenauer 对其进行了重组，现在
Python 使用单一的非递归 makefile，而不是在顶层目录和 "Python/"、
"Parser/"、"Objects/`和 :file:`Modules/" 子目录中的多个 makefile。这使
得构建 Python 更快，同时也使修改 Makefile 更加清晰和简单。

参见:

  **PEP 229** - 使用 Distutils 来构建 Python
     由 A.M. Kuchling 撰写并实现。


PEP 205: 弱引用
===============

弱引用，通过 "weakref" 模块提供，是 Python 程序员工具箱中一种较小但有
用的新数据类型。

存储一个指向对象的引用（例如，在字典或列表中）会导致该对象永久存活。
在某些特定情况下，这种行为是不符合需要的，最常见的是对象缓存，另一个是
像树这样的数据结构中的循环引用。

例如，考虑一个记忆化函数，它通过将函数的参数及其结果存储在字典中来缓存
另一个函数 "f(x)" 的结果:

   _cache = {}
   def memoize(x):
       if _cache.has_key(x):
           return _cache[x]

       retval = f(x)

       # 缓存返回的对象
       _cache[x] = retval

       return retval

这个版本适用于诸如整数之类的简单对象，但它有一个副作用；"_cache" 字典
持有返回值的引用，因此这些值在 Python 进程退出并清理之前永远不会被释放
。 对于整数来说这不是很明显，但如果 "f()" 返回一个对象或占用大量内存的
数据结构，这可能会成为一个问题。

弱引用提供了一种实现缓存的方法，不会让对象在其生命周期结束后仍然存活。
如果一个对象仅通过弱引用访问，该对象将被释放，并且弱引用将指示它所引用
的对象不再存在。 通过调用 "wr = weakref.ref(obj)" 来创建对对象 *obj*
的弱引用。 通过调用弱引用，就像调用函数一样，可以返回被引用的对象:
"wr()"。 如果对象仍然存在，它将返回被引用的对象；如果对象不再存在，则
返回 "None"。

这使得可以编写一个 "memoize()" 函数，其缓存不会使对象保持存活状态，因
为缓存中存储的是弱引用。

   _cache = {}
   def memoize(x):
       if _cache.has_key(x):
           obj = _cache[x]()
           # 如果弱引用对象仍然存在，
           # 则返回它
           if obj is not None: return obj

       retval = f(x)

       # 缓存一个弱引用
       _cache[x] = weakref.ref(retval)

       return retval

"weakref" 模块还允许创建代理对象，代理对象的行为类似于弱引用 -- 仅被代
理对象引用的对象会被解分配，但只要对象仍然存在，代理就会透明地将所有操
作转发给对象，而不需要显式调用来检索对象。 如果对象已被解分配，尝试使
用代理将引发 "weakref.ReferenceError" 异常。

   proxy = weakref.proxy(obj)
   proxy.attr   # 等同于 obj.attr
   proxy.meth() # 等同于 obj.meth()
   del obj
   proxy.attr   # 引发 weakref.ReferenceError

参见:

  **PEP 205** - 弱引用
     由 Fred L. Drake, Jr 撰写并实现。


PEP 232: 函数属性
=================

在 Python 2.1 中，函数现在可以附加任意信息。人们经常使用文档字符串来保
存有关函数和方法的信息，因为 "__doc__" 属性是唯一可以将任何信息附加到
函数上的方式。例如，在 Zope 网络应用服务器中，函数通过拥有文档字符串来
标记为公共访问安全，在 John Aycock 的 SPARK 解析框架中，文档字符串包含
要解析的 BNF 语法的部分。这种过载是不幸的，因为文档字符串实际上是用来
保存函数文档的；例如，这意味着你不能正确地为 Zope 中预期用于私有用途的
函数编写文档。

现在可以使用常规的 Python 语法在函数上设置和检索任意属性:

   def f(): pass

   f.publish = 1
   f.secure = 1
   f.grammar = "A ::= B (C D)*"

包含属性的字典可以作为函数的 "__dict__" 访问。 与类实例的 "__dict__"
属性不同，在函数中，您实际上可以为 "__dict__" 分配一个新的字典，尽管新
值仅限于普通的 Python 字典；您 *不能* 狡猾地将其设置为 "UserDict" 实例
，或任何其他行为类似映射的随机对象。

参见:

  **PEP 232** - 函数属性
     由 Barry Warsaw 撰写并实现


PEP 235: 在大小写不敏感的平台上导入模块
=======================================

一些操作系统的文件系统是大小写不敏感的，MacOS 和 Windows 是主要的例子
；在这些系统上，无法区分文件名 "FILE.PY" 和 "file.py"，尽管它们确实以
原始大小写存储文件名（它们也是保留大小写的）。

在 Python 2.1 中，"import" 语句可以在不区分大小写的平台上模拟大小写敏
感性。 现在，Python 默认搜索第一个大小写敏感匹配的文件，如果找不到这样
的文件，就会引发 "ImportError"，因此 "import file" 不会导入名为
"FILE.PY" 的模块。 在启动 Python 解释器之前，可以通过设置
"PYTHONCASEOK" 环境变量来请求大小写不敏感匹配。


PEP 217: 交互模式显示钩子
=========================

在交互模式下使用 Python 解释器时，命令的输出是通过内置的 "repr()" 函数
显示的。 在 Python 2.1 中，可以将变量 "sys.displayhook()" 设置为一个可
调用对象，该对象将在代替 "repr()" 函数被调用。 例如，你可以将其设置为
一个特殊的美化打印函数:

   >>> # 创建一个递归的数据结构
   ... L = [1,2,3]
   >>> L.append(L)
   >>> L # 显示 Python 的默认输出
   [1, 2, 3, [...]]
   >>> # 使用 pprint.pprint() 作为显示函数
   ... import sys, pprint
   >>> sys.displayhook = pprint.pprint
   >>> L
   [1, 2, 3,  <Recursion on list with id=135143996>]
   >>>

参见:

  **PEP 217** - 用于交互模式的显示钩子
     由 Moshe Zadka 撰写并实现


PEP 208: 新的强制转换模型
=========================

在 C 级别上的数值类型转换方法进行了重大修改。 这只会影响编写 Python C
扩展的作者，使他们在编写支持数值运算的扩展类型时有更多的灵活性。

扩展类型现在可以在其 "PyTypeObject" 结构中设置类型标志
"Py_TPFLAGS_CHECKTYPES"，以表明它们支持新的强制模型。 在此类扩展类型中
，数字槽函数不再假定它们将得到两个相同类型的参数；相反，它们可能会得到
两个不同类型的参数，然后可以执行自己的内部强制。如果槽函数传递给它一个
无法处理的类型，它可以通过返回一个指向 "Py_NotImplemented" 单一值的引
用来表示失败。 然后将尝试其他类型的数值函数，也许它们可以处理该操作；
如果其他类型也返回 "Py_NotImplemented"，那么将引发 "TypeError"。 用
Python 写的数值方法也可以返回 "Py_NotImplemented"，导致解释器当作该方
法不存在（也许会引发 "TypeError"，也许会尝试另一个对象的数值方法）。

参见:

  **PEP 208** - 改写强制转换模型
     由 Neil Schemenauer 编写和实现，基于 Marc-André Lemburg 的早期工
     作。阅读这部分内容可以了解数值运算在 C 级别上现在如何处理的细节。


PEP 241: Python 包中的元数据
============================

Python 用户经常抱怨的一个问题是不存在包含所有 Python 模块的单一类目。
位于 "www.vex.net/parnassus/" 上 T. Middleton 的 Vaults of Parnassus
(2009 年 2 月已停用，可在 Internet Archive Wayback Machine 上查阅) 是
最大的 Python 模块类目，但在 Vaults 上注册软件只是个可选项，很多人都懒
得这样做。

作为解决这个问题的第一步，使用 Distutils **sdist** 命令打包的 Python
软件将包含一个名为 "PKG-INFO" 的文件，其中包含有关包的信息，如名称、版
本和作者（在目录编制术语中称为元数据）。"PKG-INFO" 文件可以包含的字段
的完整列表见 **PEP 241**。随着人们开始使用 Python 2.1 打包他们的软件，
越来越多的包将包含元数据，从而使得构建自动化目录系统并进行实验成为可能
。通过积累经验，也许有可能设计一个真正好的目录系统，然后在 Python 2.2
中支持它。例如，Distutils 的 **sdist** 和 **bdist_*** 命令可以支持一个
"upload" 选项，自动将你的包上传到目录服务器。

即使你不使用 Python 2.1，你也可以开始创建包含 "PKG-INFO" 的包，因为
Distutils 的新版本将为早期 Python 版本的用户发布。Distutils 1.0.2 版本
包含了 **PEP 241** 所描述的更改，以及各种错误修复和增强功能。可以从
Distutils SIG 上获取该版本
https://www.python.org/community/sigs/current/distutils-sig/ 。

参见:

  **PEP 241** - 针对 Python 软件包的元数据
     由 A.M. Kuchling 撰写并实现。

  **PEP 243** - 模块仓库上传机制
     由 Sean Reifschneider 撰写，这个 PEP 草案描述了用于将 Python 软件
     包上传到一个中心服务器的建议机制。


新增和改进的模块
================

* Ka-Ping Yee 贡献了两个新模块: "inspect.py"，用于获取有关正在运行的
  Python 代码的信息，以及 "pydoc.py"，用于交互式地将文档字符串转换为
  HTML 或文本。 此外，作为一个额外的功能，"Tools/scripts/pydoc" 现在会
  自动安装，并使用 "pydoc.py" 来显示给定 Python 模块、包或类名的文档。
  例如，"pydoc xml.dom" 会显示如下内容:

     Python Library Documentation: package xml.dom in xml

     NAME
         xml.dom - W3C Document Object Model implementation for Python.

     FILE
         /usr/local/lib/python2.1/xml/dom/__init__.pyc

     DESCRIPTION
         The Python mapping of the Document Object Model is documented in the
         Python Library Reference in the section on the xml.dom package.

         This package contains the following modules:
           ...

  "pydoc" 还包括一个基于 Tk 的交互式帮助浏览器。"pydoc" 很快会让人上瘾
  ；试试看！

* 两个不同的单元测试模块被添加到标准库中。"doctest" 模块，由 Tim
  Peters 贡献，提供了一个基于运行嵌入在文档字符串中的示例并将结果与预
  期输出进行比较的测试框架。PyUnit，由 Steve Purcell 贡献，是一个受到
  JUnit 启发的单元测试框架，而 JUnit 则是对 Kent Beck 的 Smalltalk 测
  试框架的改编。更多关于 PyUnit 的信息，请参阅
  https://pyunit.sourceforge.net/ 。

* "difflib" 模块包含一个类，即 "SequenceMatcher"，用于比较两个序列，并
  计算将一个序列转换为另一个序列所需的变化。 例如，该模块可用于编写与
  Unix **diff** 程序类似的工具，事实上，示例程序
  "Tools/scripts/ndiff.py" 演示了如何编写这样的脚本。

* "curses.panel"，是 ncurses 和 SYSV curses 一部分的 panel 库的包装器
  ，由 Thomas Gellekum 贡献。panel 库为窗口提供了深度特性。窗口可以在
  深度顺序中向上或向下移动，panel 库会计算出面板的重叠位置和哪些部分是
  可见的。

* PyXML 包自 Python 2.0 以来经历了几次发布，Python 2.1 包含了更新版本
  的 "xml" 包。一些值得注意的更改包括支持 Expat 1.2 及更高版本，Expat
  解析器能够处理 Python 支持的任何编码的文件，以及对 SAX、DOM 和
  "minidom" 模块的各种错误修复。

* Ka-Ping Yee 还贡献了另一个用于处理未捕获异常的钩子。
  "sys.excepthook()" 可以设置为一个可调用对象。当异常未被任何
  "try"..."except" 块捕获时，异常将传递给 "sys.excepthook()"，它可以执
  行任何需要的操作。在第九届 Python 会议上，他演示了这个钩子的一个应用
  ：打印扩展的回溯信息，不仅列出堆栈帧，还列出每个帧的函数参数和局部变
  量。

* "time" 模块中的各种函数，如 "asctime()" 和 "localtime()"，需要一个包
  含自纪元以来的时间以秒为单位的浮点参数。这些函数最常见的用途是处理当
  前时间，因此浮点参数现在是可选的；当没有提供值时，将使用当前时间。例
  如，日志文件条目通常需要一个包含当前时间的字符串；在 Python 2.1 中，
  可以使用 "time.asctime()"，而不是之前需要的较长的
  "time.asctime(time.localtime(time.time()))"。

  此更改由 Thomas Wouters 提出并实现。

* "ftplib" 模块现在默认以被动模式检索文件，因为被动模式在防火墙后面更
  可能正常工作。这一请求来自 Debian 错误跟踪系统，因为其他 Debian 包使
  用 "ftplib" 来检索文件，但在防火墙后面无法正常工作。由于 Netscape 默
  认使用被动模式且几乎没有人抱怨，因此认为这不太可能会对任何人造成问题
  。但如果被动模式不适合你的应用程序或网络设置，可以调用 FTP 对象的
  "set_pasv(0)" 来禁用被动模式。

* 对原始套接字访问的支持已添加到 "socket" 模块中，由 Grant Edwards 贡
  献。

* "pstats" 模块现在包含一个简单的交互式统计浏览器，用于显示 Python 程
  序的时间分析结果，当该模块作为脚本运行时调用。此功能由 Eric S.
  Raymond 贡献。

* 新增了一个依赖于实现的函数 "sys._getframe([depth])"，用于从当前调用
  堆栈中返回给定的帧对象。"sys._getframe`返回调用堆栈顶部的帧对象；如
  果提供了可选的整数参数 depth，则该函数返回堆栈顶部以下 depth 层的帧
  。例如，``sys._getframe(1)`()" 返回调用者的帧对象。

  这个函数仅存在于 CPython 中，不存在于 Jython 或 .NET 实现中。请将其
  用于调试，并避免将其放入生产代码中。


其他的改变和修正
================

由于较短的发布周期，Python 2.1 中的较小更改相对较少。通过搜索 CVS 更改
日志，发现应用了 117 个补丁并修复了 136 个错误；这两个数字都可能是低估
的。一些较为显著的更改包括：

* 现在可以选择使用一个专门的对象分配器，该分配器应比系统的 "malloc()"
  更快且具有更少的内存开销。该分配器使用 C 语言的 "malloc()" 函数来获
  取大型内存池，然后从这些池中满足较小的内存请求。可以通过向
  **configure** 脚本提供 "--with-pymalloc" 选项来启用该分配器；有关实
  现细节，请参阅 "Objects/obmalloc.c"。

  C 扩展模块的作者应该在启用对象分配器的情况下测试他们的代码，因为一些
  不正确的代码可能会被破坏，导致运行时的核心转储。 在 Python 的 C API
  中有许多内存分配函数，它们以前只是 C 库的 "malloc()" 和 "free()" 的
  别名，这意味着如果您不小心调用了不匹配的函数，错误是不会被注意到的。
  启用对象分配器后，这些函数不再是 "malloc()" 和 "free()" 的别名，调用
  错误的函数释放内存将导致核心转储。 例如，如果使用 "PyMem_New" 分配了
  内存，就必须使用 "PyMem_Del()" 而不是 "free()" 释放内存。 Python 附
  带的一些模块就有这样的问题，必须进行修复；毫无疑问，还有更多的第三方
  模块会有同样的问题。

  对象分配器由 Vladimir Marangozov 贡献。

* 由于人们经常抱怨面向行的文件 I/O 速度缓慢，并且它经常被用作一个简单
  的基准测试，其速度已经得到了改进。 因此，文件对象的 "readline()" 方
  法被重写，以实现更快的速度。 具体的速度提升因平台而异，取决于 C 库的
  "getc()" 有多慢，但大约提升了66%，在某些特定的操作系统上可能更快。
  Tim Peters 在 comp.lang.python 的讨论中受到了启发，进行了许多基准测
  试和编码修改。

  新增了一个模块和文件对象的方法，由 Jeff Epler 贡献。 新方法
  "xreadlines()" 类似于现有的内置方法 "xrange()"。 "xreadlines()" 返回
  一个不透明的序列对象，该对象仅支持迭代，每次迭代读取一行，而不像现有
  的 "readlines()" 方法那样将整个文件读入内存。 你可以像这样使用它:

     for line in sys.stdin.xreadlines():
         # ... 对每一行执行某些操作 ...
         ...

  有关行 I/O 更改的更详细讨论，请参阅 2001 年 1 月 1 日至 15 日的
  python-dev 摘要 https://mail.python.org/pipermail/python-
  dev/2001-January/ 。

* 给字典添加了一个新方法 "popitem()"，用于破坏性地迭代字典的内容；这对
  于大字典来说可能更快，因为不需要构建包含所有键或值的列表。
  "D.popitem()" 从字典``D``中移除一个随机的``(key, value)``键值对，并
  将其作为一个 2 元组返回。 此功能主要由 Tim Peters 和 Guido van
  Rossum 实现，基于 Moshe Zadka 的建议和初步补丁。

* 模块现在可以通过定义一个 "__all__" 属性来控制使用 "from module
  import *" 时导入的名称。 一个常见的抱怨是，如果模块导入了其他模块，
  例如 "sys" 或 "string"，使用 "from module import *" 会将它们添加到导
  入模块的命名空间中。 为了解决这个问题，只需在 "__all__" 模块中列出公
  共名称即可:

     # 列出公有名称
     __all__ = ['Database', 'open']

  此补丁的更严格版本最初由 Ben Wolfson 提出并实现，但在经过一些
  python-dev 讨论后，最终版本被修改为较弱的版本并提交。

* 以前对字符串应用 "repr()" 时，对于不可打印字符使用八进制转义符；例如
  ，换行符表示为 "'\012'"。这是 Python 从 C 语言继承而来的遗留特性，但
  如今八进制的实际用途非常有限。Ka-Ping Yee 建议使用十六进制转义符代替
  八进制，并使用 "\n"、"\t"、"\r" 等转义符表示适当的字符，并实现了这种
  新的格式。

* 在编译时检测到的语法错误现在可以引发包含错误文件名和行号的异常，这是
  Jeremy Hylton 进行的编译器重组的一个令人愉快的副作用。

* 导入其他模块的 C 扩展已更改为使用 "PyImport_ImportModule()"，这意味
  着它们将使用已安装的任何导入钩子。这对于需要从 C 代码导入其他模块的
  第三方扩展也同样鼓励使用。

* 由于 Fredrik Lundh 的努力，Unicode 字符数据库的大小又减少了 340K。

* 一些新移植版本被贡献：MacOS X（由 Steven Majewski 贡献），Cygwin（由
  Jason Tishler 贡献），RISCOS（由 Dietmar Schwertberger 贡献），以及
  Unixware 7（由 Billy G. Allie 贡献）。

此外还有一份由次要的程序错误修复、次要的内存泄漏、文档字符串编辑和其他
调整组成的常规清单，因过于冗长而不值得逐项列出；如果你想了解完整细节请
参阅 CVS 日志。


致谢
====

作者感谢以下人员对本文的各种草案提出建议： Graeme Cross, David
Goodger, Jay Graves, Michael Hudson, Marc-André Lemburg, Fredrik
Lundh, Neil Schemenauer, Thomas Wouters.
