Python 2.5 有什么新变化

作者:

A.M. Kuchling

本文介绍了 Python 2.5 的新增特性。 Python 2.5 预定的最终发布时间为 2006 年 8 月;PEP 356 描述了预定的发布日程。 Python 2.5 实际发布于 2006 年 9 月 19 日。

The changes in Python 2.5 are an interesting mix of language and library improvements. The library enhancements will be more important to Python's user community, I think, because several widely useful packages were added. New modules include ElementTree for XML processing (xml.etree.ElementTree), the SQLite database module (sqlite3), and the ctypes module for calling C functions.

语言变更具有中等重要性。 一些令人愉悦的新功能被添加进来,但其中大多数并不是你每天都会使用的功能。 条件表达式终于以新颖的语法被添加到语言中;参见 PEP 308: 条件表达式 一节。 新的 'with' 语句将使编写清理代码变得更容易 (PEP 343: "with" 语句)。 现在可以将值传递给生成器 (PEP 342: 生成器的新特性)。 导入现在可以明确为绝对或相对 (PEP 328: 绝对导入和相对导入)。 一些异常处理的边缘情况得到了更好的处理 (PEP 341: 统一 try/except/finally)。 所有这些改进都是有价值的,但它们都是对特定语言功能的改进;它们都不是对 Python 语义的广泛修改。

除了语言和库的添加之外,整个源代码树中还进行了其他改进和错误修复。通过搜索SVN变更日志发现,在Python 2.4和2.5之间应用了353个补丁并修复了458个错误。(这两个数字都可能是低估的。)

本文并不试图成为新功能的完整规范;相反,通过有帮助的示例简要介绍了这些变更。有关完整详情,你应始终参考Python 2.5的文档,网址为https://docs.pyth.onl。如果你想了解完整的实现和设计原理,请参考特定新功能的PEP。

欢迎对本文档提出评论、建议和错误报告;请通过电子邮件发送给作者或在Python错误跟踪器中打开一个错误报告。

PEP 308: 条件表达式

长期以来,人们一直要求有一种方法来编写条件表达式,这种表达式根据布尔值的真或假返回值A或值B。条件表达式允许你编写一个赋值语句,其效果与以下相同:

if condition:
    x = true_value
else:
    x = false_value

在python-dev和comp.lang.python上,关于语法的无尽乏味讨论已经屡见不鲜。甚至进行了一次投票,发现大多数投票者希望以某种形式引入条件表达式,但没有一种语法获得了明显多数的支持。候选语法包括C语言的``cond ? true_v : false_v``、if cond then true_v else false_v 以及16种其他变体。

Guido van Rossum 最终选择了一种令人惊讶的语法:

x = true_value if condition else false_value

评估仍然像现有的布尔表达式一样是惰性的,因此评估顺序会有些跳跃。中间的 condition 表达式首先被评估,true_value 表达式只有在条件为真时才会被评估。同样,false_value 表达式只有在条件为假时才会被评估。

这种语法可能看起来奇怪且倒置;为什么条件要放在表达式的*中间*,而不是像C语言中的``c ? x : y``那样放在前面?这一决定是通过将新语法应用于标准库中的模块,并查看生成的代码的可读性来验证的。在许多使用条件表达式的情况下,一个值似乎是'常见情况',而另一个值是'特殊情况',仅在条件不满足的罕见情况下使用。条件语法使这种模式更加明显:

contents = ((doc + '\n') if doc else '')

我将上述声明理解为“通常 contents 被赋值为 doc+'\n';有时 doc 为空,在这种情况下返回空字符串。”我怀疑在不存在明显常见和不常见情况的地方,我不会经常使用条件表达式。

曾经有过一些讨论,关于是否应该要求在条件表达式周围加上括号。决定是不在 Python 语言的语法中要求括号,但出于风格考虑,我认为你应该总是使用它们。考虑以下两个语句:

# 第一个版本 -- 无括号
level = 1 if logging else 0

# 第二个版本 -- 有括号
level = (1 if logging else 0)

在第一个版本中,我认为读者的视线可能会将语句分为'level = 1'、'if logging'、'else 0',并认为条件决定了是否对*level*进行赋值。在我看来,第二个版本读起来更好,因为它清楚地表明赋值始终执行,只是在两个值之间进行选择。

包含括号还有一个原因:一些列表推导式和lambda表达式的奇怪组合可能看起来像错误的条件表达式。参见 PEP 308 了解一些示例。如果你在条件表达式周围加上括号,就不会遇到这种情况。

参见

PEP 308 - 条件表达式

PEP 由 Guido van Rossum 和 Raymond D 撰写,由 Thomas Wouters 实现。

PEP 309: 部分功能应用

functools 模块旨在包含用于函数式编程风格的工具。

One useful tool in this module is the partial() function. For programs written in a functional style, you'll sometimes want to construct variants of existing functions that have some of the parameters filled in. Consider a Python function f(a, b, c); you could create a new function g(b, c) that was equivalent to f(1, b, c). This is called "partial function application".

partial() takes the arguments (function, arg1, arg2, ... kwarg1=value1, kwarg2=value2). The resulting object is callable, so you can just call it to invoke function with the filled-in arguments.

这里有一个很小但很现实的例子:

import functools

def log (message, subsystem):
    "将 'message' 的内容写到指定的子系统。"
    print '%s: %s' % (subsystem, message)
    ...

server_log = functools.partial(log, subsystem='server')
server_log('Unable to open socket')

Here's another example, from a program that uses PyGTK. Here a context-sensitive pop-up menu is being constructed dynamically. The callback provided for the menu option is a partially applied version of the open_item() method, where the first argument has been provided.

...
class Application:
    def open_item(self, path):
       ...
    def init (self):
        open_func = functools.partial(self.open_item, item_path)
        popup_menu.append( ("Open", open_func, 1) )

Another function in the functools module is the update_wrapper(wrapper, wrapped) function that helps you write well-behaved decorators. update_wrapper() copies the name, module, and docstring attribute to a wrapper function so that tracebacks inside the wrapped function are easier to understand. For example, you might write:

def my_decorator(f):
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    functools.update_wrapper(wrapper, f)
    return wrapper

wraps() is a decorator that can be used inside your own decorators to copy the wrapped function's information. An alternate version of the previous example would be:

def my_decorator(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        print 'Calling decorated function'
        return f(*args, **kwds)
    return wrapper

参见

PEP 309 - 部分函数应用

PEP由 Peter Harris 提出并撰写;由 Hye-Shik Chang 和 Nick Coghlan 实现,并由 Raymond Hettinger 适配。

PEP 314: Python软件包的元数据 v1.1

Some simple dependency support was added to Distutils. The setup() function now has requires, provides, and obsoletes keyword parameters. When you build a source distribution using the sdist command, the dependency information will be recorded in the PKG-INFO file.

另一个新的关键字参数是 download_url,它应该设置为包源代码的 URL。这意味着现在可以查找包索引中的条目,确定包的依赖关系,并下载所需的包。:

VERSION = '1.0'
setup(name='PyPackage',
      version=VERSION,
      requires=['numarray', 'zlib (>=1.1.4)'],
      obsoletes=['OldPackage']
      download_url=('http://www.example.com/pypackage/dist/pkg-%s.tar.gz'
                    % VERSION),
     )

Python 包索引 https://pypi.org 的另一个新增强功能是存储包的源代码和二进制存档。新的 upload Distutils 命令将上传包到仓库。

在包可以上传之前,你必须能够使用 sdist Distutils 命令构建分发。一旦那个工作完成,你可以运行 python setup.py upload 将你的包添加到 PyPI 存档中。可选地,你可以通过提供 --sign--identity 选项来对包进行 GPG 签名。

包上传操作由 Martin von Löwis 和 Richard Jones 实现。

参见

PEP 314 - Python软件包的元数据 v1.1

PEP 由 A.M. Kuchling, Richard Jones 和 Fred Drake 提出并撰写,由 Richard Jones 和 Fred Drake 实现。

PEP 328: 绝对导入和相对导入

PEP 328 的较简单部分已在 Python 2.4 中实现:现在可以用圆括号将使用 from ... import ... 语句导入的名称括起来,以便能够更容易地导入大量不同的名称。

更复杂的部分已在 Python 2.5 中实现:可以指定使用绝对的或相对于包的导入方式来导入模块。 计划在未来的 Python 版本中将绝对导入方式设为默认。

比如说你有这样一个包目录:

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

This defines a package named pkg containing the pkg.main and pkg.string submodules.

Consider the code in the main.py module. What happens if it executes the statement import string? In Python 2.4 and earlier, it will first look in the package's directory to perform a relative import, finds pkg/string.py, imports the contents of that file as the pkg.string module, and that module is bound to the name string in the pkg.main module's namespace.

That's fine if pkg.string was what you wanted. But what if you wanted Python's standard string module? There's no clean way to ignore pkg.string and look for the standard module; generally you had to look at the contents of sys.modules, which is slightly unclean. Holger Krekel's py.std package provides a tidier way to perform imports from the standard library, import py; py.std.string.join(), but that package isn't available on all Python installations.

Reading code which relies on relative imports is also less clear, because a reader may be confused about which module, string or pkg.string, is intended to be used. Python users soon learned not to duplicate the names of standard library modules in the names of their packages' submodules, but you can't protect against having your submodule's name being used for a new module added in a future version of Python.

在 Python 2.5 中,你可以通过使用 from __future__ import absolute_import 指令将 import 的行为切换为绝对导入。这种绝对导入行为将在未来版本(可能是 Python 2.7)中成为默认行为。一旦绝对导入成为默认行为,import string 将始终找到标准库的版本。建议用户尽可能开始使用绝对导入,因此最好在代码中开始写 from pkg import string

通过在使用 from ... import 形式时在模块名称前添加一个前导点,仍然可以进行相对导入:

# 从 pkg.string 导入名称
from .string import name1, name2
# 导入 pkg.string
from . import string

This imports the string module relative to the current package, so in pkg.main this will import name1 and name2 from pkg.string. Additional leading periods perform the relative import starting from the parent of the current package. For example, code in the A.B.C module can do:

from . import D                 # 导入 A.B.D
from .. import E                # 导入 A.E
from ..F import G               # 导入 A.F.G

开头的句点不可用于 import 语句的 import modname 形式,只能用于 from ... import 形式。

参见

PEP 328 - 导入:多行和绝对/相对导入

PEP 由 Aahz 撰写,由 Thomas Wouters 实现。

https://pylib.readthedocs.io/

The py library by Holger Krekel, which contains the py.std package.

PEP 338: 将模块作为脚本执行

Python 2.4 中添加的 -m 开关用于将模块作为脚本执行,获得了一些新能力。这个开关现在不再使用 Python 解释器内部的 C 代码实现,而是使用一个新模块 runpy 中的实现。

The runpy module implements a more sophisticated import mechanism so that it's now possible to run modules in a package such as pychecker.checker. The module also supports alternative import mechanisms such as the zipimport module. This means you can add a .zip archive's path to sys.path and then use the -m switch to execute code from the archive.

参见

PEP 338 - 将模块作为脚本执行

PEP 由 Nick Coghlan 撰写并实现。

PEP 341: 统一 try/except/finally

直到 Python 2.5,try 语句有两种形式。你可以使用 finally 块确保代码总是被执行,或者使用一个或多个 except 块来捕获特定异常。你不能同时组合 except 块和 finally 块,因为生成正确字节码的合并版本很复杂,并且不清楚合并语句的语义应该是什么。

Guido van Rossum 花了一些时间研究 Java,后者支持组合 except 块和 finally 块的等价物,这澄清了该语句应该是什么意思。在 Python 2.5 中,你现在可以写:

try:
    block-1 ...
except Exception1:
    handler-1 ...
except Exception2:
    handler-2 ...
else:
    else-block
finally:
    final-block

The code in block-1 is executed. If the code raises an exception, the various except blocks are tested: if the exception is of class Exception1, handler-1 is executed; otherwise if it's of class Exception2, handler-2 is executed, and so forth. If no exception is raised, the else-block is executed.

无论之前发生了什么,一旦代码块完成并且处理了任何引发的异常,final-block 都会被执行一次。即使异常处理程序或 else-block 中出现错误并引发了新的异常,final-block 中的代码仍然会运行。

参见

PEP 341 - 统一 try-except 和 try-finally

PEP 由 Georg Brandl 撰写,由 Thomas Lee 实现。

PEP 342: 生成器的新特性

Python 2.5 添加了一种简单的方法来将值 传入 生成器。如在 Python 2.3 中引入的,生成器仅产生输出;一旦生成器的代码被调用以创建迭代器,当其执行恢复时,无法将任何新信息传递到函数中。有时能够传递一些信息会很有用。对此的权宜之计包括让生成器的代码查看全局变量,然后更改全局变量的值,或者传入一些可变对象,然后调用者修改它。

为了刷新你对基本生成器的记忆,这里有一个简单的例子:

def counter (maximum):
    i = 0
    while i < maximum:
        yield i
        i += 1

当你调用 counter(10) 时,结果是一个迭代器,它返回从 0 到 9 的值。在遇到 yield 语句时,迭代器返回提供的值并挂起函数的执行,保留局部变量。执行在下次调用迭代器的 next() 方法时恢复,从 yield 语句之后开始。

在 Python 2.3 中,yield 是一个语句;它不返回任何值。在 2.5 中,yield 现在是一个表达式,返回一个可以赋值给变量或进行其他操作的值:

val = (yield i)

我建议在处理返回值时,总是将 yield 表达式用括号括起来,如上例所示。括号并非总是必要,但总是添加它们比记住何时需要它们要容易。

(PEP 342 解释了确切的规则,即 yield-表达式必须总是括起来,除非它出现在赋值右侧的顶层表达式中。这意味着你可以写 val = yield i,但在有操作时必须使用括号,如 val = (yield i) + 12。)

通过调用生成器的 send(value) 方法将值发送到生成器中。然后生成器的代码继续执行,yield 表达式返回指定的 value。如果调用常规的 next() 方法,yield 返回 None

以下是修改后的示例,允许更改内部计数器的值。

def counter (maximum):
    i = 0
    while i < maximum:
        val = (yield i)
        # 如果提供了值,更改计数器
        if val is not None:
            i = val
        else:
            i += 1

以下是更改计数器的示例:

>>> it = counter(10)
>>> print it.next()
0
>>> print it.next()
1
>>> print it.send(8)
8
>>> print it.next()
9
>>> print it.next()
Traceback (most recent call last):
  File "t.py", line 15, in ?
    print it.next()
StopIteration

yield will usually return None, so you should always check for this case. Don't just use its value in expressions unless you're sure that the send() method will be the only method used to resume your generator function.

In addition to send(), there are two other new methods on generators:

  • throw(type, value=None, traceback=None) 用于在生成器内部引发异常;异常由 yield 表达式在生成器执行暂停的地方引发。

  • close() raises a new GeneratorExit exception inside the generator to terminate the iteration. On receiving this exception, the generator's code must either raise GeneratorExit or StopIteration. Catching the GeneratorExit exception and returning a value is illegal and will trigger a RuntimeError; if the function raises some other exception, that exception is propagated to the caller. close() will also be called by Python's garbage collector when the generator is garbage-collected.

    如果你需要在 GeneratorExit 发生的时候运行清理代码,我建议使用 try: ... finally: 组合来代替捕获 GeneratorExit

这些改变的累积效应是,让生成器从单向的信息生产者变成了既是生产者,又是消费者。

生成器还可以成为 协程,这是一种更通用的子程序形式。子程序从一个点进入并在另一个点退出(函数顶部和 return 语句),但协程可以在许多不同的点进入、退出和恢复(yield 语句)。我们需要找出在 Python 中有效使用协程的模式。

The addition of the close() method has one side effect that isn't obvious. close() is called when a generator is garbage-collected, so this means the generator's code gets one last chance to run before the generator is destroyed. This last chance means that try...finally statements in generators can now be guaranteed to work; the finally clause will now always get a chance to run. The syntactic restriction that you couldn't mix yield statements with a try...finally suite has therefore been removed. This seems like a minor bit of language trivia, but using generators and try...finally is actually necessary in order to implement the with statement described by PEP 343. I'll look at this new statement in the following section.

Another even more esoteric effect of this change: previously, the gi_frame attribute of a generator was always a frame object. It's now possible for gi_frame to be None once the generator has been exhausted.

参见

PEP 342 - 通过增强型生成器实现协程

PEP 由 Guido van Rossum 和 Phillip J. Eby 撰写,由 Phillip J. Eby 实现。包括一些更高级的使用生成器作为协程的示例。

这些功能的早期版本在 PEP 288 (由 Raymond Hettinger 撰写) 和 PEP 325 (由 Samuele Pedroni 撰写)中提出。

https://en.wikipedia.org/wiki/Coroutine

协程的Wikipedia条目。

https://web.archive.org/web/20160321211320/http://www.sidhe.org/~dan/blog/archives/000178.html

基于 Perl 视角对协程的介绍,由 Dan Sugalski 撰写。

PEP 343: "with" 语句

'with' 语句澄清了之前使用 try...finally 块来确保执行清理代码的代码。在本节中,我将讨论该语句的常见用法。在下一节中,我将探讨实现细节,并展示如何编写与该语句一起使用的对象。

'with' 语句是一个新的控制流结构,其基本结构如下:

with expression [as variable]:
    with-block

表达式被评估,并且应该生成一个支持上下文管理协议的对象(即具有 __enter__()__exit__() 方法的对象)。

在执行 with-block 之前调用对象的 __enter__() 方法,因此可以运行设置代码。它还可以返回一个值,该值绑定到名称 variable*(如果给出)。请注意,*variable 并不是被赋值为 expression 的结果。

with-block 执行完成后,调用对象的 __exit__() 方法,即使块引发了异常,也可以运行清理代码。

要在 Python 2.5 中启用该语句,你需要向你的模块添加以下指令:

from __future__ import with_statement

该语句在Python 2.6 中始终启用。

一些标准 Python 对象现在已支持上下文管理协议并可被用于 'with' 语句。 文件对象就是一个例子:

with open('/etc/passwd', 'r') as f:
    for line in f:
        print line
        ... 更多处理代码 ...

在此语句被执行之后,文件对象 f 将被自动关闭,即使是当 for 循环在代码块中间位置引发了异常的时候也是如此。

备注

在此情况下,f 就是由 open() 所创建的对象,因为 __enter__() 会返回 self

threading 模块的加锁和条件变量也支持 'with' 语句:

lock = threading.Lock()
with lock:
    # 关键代码段
    ...

这个锁会在代码块被执行之前锁定并总是会在代码块完成之后释放。

The new localcontext() function in the decimal module makes it easy to save and restore the current decimal context, which encapsulates the desired precision and rounding characteristics for computations:

from decimal import Decimal, Context, localcontext

# 使用默认精度 28 位显示
v = Decimal('578')
print v.sqrt()

with localcontext(Context(prec=16)):
    # 此块中的所有代码使用 16 位精度。
    # 块退出时恢复原始上下文。
    print v.sqrt()

编写上下文管理器

在幕后,'with' 语句相当复杂。大多数人只会与现有对象一起使用 'with',不需要了解这些细节,所以如果你愿意,可以跳过本节的其余部分。新对象的作者需要理解底层实现的细节,应该继续阅读。

在更高层级上对于上下文管理器协议的解释:

  • 表达式将被求值,并应生成一个称为“上下文管理器”的对象。上下文管理器必须具有 __enter__()__exit__() 方法。

  • 调用上下文管理器的 __enter__() 方法。返回的值被赋给 VAR。如果没有 'as VAR' 子句,该值将被丢弃。

  • BLOCK 中的代码会被执行。

  • 如果 BLOCK 引发异常,将调用 __exit__(type, value, traceback) 方法,并传入异常详细信息,这些值与 sys.exc_info() 返回的值相同。该方法的返回值控制是否重新抛出异常:任何假值将重新抛出异常,而 True 将导致异常被抑制。通常情况下,你很少会想要抑制异常,因为如果你这么做,包含 'with' 语句的代码作者将永远不会意识到出了问题。

  • 如果 BLOCK 没有引发异常,仍然会调用 __exit__() 方法,但 typevaluetraceback 都是 None

让我们通过一个例子来思考。我将不展示详细的代码,而只是概述支持事务的数据库所需的方法。

(对于不熟悉数据库术语的人:对数据库的一系列更改被组合成一个事务。事务可以被提交,意味着所有更改都被写入数据库,或者被回滚,意味着所有更改都被丢弃,数据库保持不变。更多信息请参阅任何数据库教材。)

假设有一个表示数据库连接的对象。我们的目标将是让用户编写如下代码:

db_connection = DatabaseConnection()
with db_connection as cursor:
    cursor.execute('insert into ...')
    cursor.execute('delete from ...')
    # ... 更多操作 ...

The transaction should be committed if the code in the block runs flawlessly or rolled back if there's an exception. Here's the basic interface for DatabaseConnection that I'll assume:

class DatabaseConnection:
    # 数据库接口
    def cursor(self):
        "返回一个游标对象并开始一个新的事务"
    def commit(self):
        "提交当前事务"
    def rollback(self):
        "回滚当前事务"

__enter__() 方法非常简单,只需开始一个新的事务。对于这个应用程序,生成的游标对象将是一个有用的结果,因此该方法将返回它。用户可以在他们的 'with' 语句中添加 as cursor 来将游标绑定到一个变量名。:

class DatabaseConnection:
    ...
    def __enter__(self):
        # 开始一个新事务的代码
        cursor = self.cursor()
        return cursor

__exit__() 方法是最复杂的,因为大部分工作需要在这里完成。该方法需要检查是否发生了异常。如果没有异常,事务将被提交。如果发生了异常,事务将被回滚。

在下面的代码中,执行将直接从函数末尾跳出,返回默认值 NoneNone 是假值,因此异常将自动重新抛出。如果你愿意,你可以更明确地添加一个 return 语句在标记的位置。:

class DatabaseConnection:
    ...
    def __exit__ (self, type, value, tb):
        if tb is None:
            # 没有异常,因此提交
            self.commit()
        else:
            # 发生异常,因此回滚。
            self.rollback()
            # 返回 False

contextlib 模块

新的 contextlib 模块提供了一些函数和一个装饰器,用于编写与 'with' 语句一起使用的对象。

The decorator is called @~contextlib.contextmanager, and lets you write a single generator function instead of defining a new class. The generator should yield exactly one value. The code up to the yield will be executed as the __enter__() method, and the value yielded will be the method's return value that will get bound to the variable in the 'with' statement's as clause, if any. The code after the yield will be executed in the __exit__() method. Any exception raised in the block will be raised by the yield statement.

上一节中的数据库示例可以使用这个装饰器编写为:

from contextlib import contextmanager

@contextmanager
def db_transaction (connection):
    cursor = connection.cursor()
    try:
        yield cursor
    except:
        connection.rollback()
        raise
    else:
        connection.commit()

db = DatabaseConnection()
with db_transaction(db) as cursor:
    ...

contextlib 模块还有一个``nested(mgr1, mgr2, ...)``函数,它可以将多个上下文管理器组合在一起,这样你就不需要编写嵌套的'with'语句。在这个例子中,单个'with'语句既启动数据库事务又获取线程锁:

lock = threading.Lock()
with nested (db_transaction(db), lock) as (cursor, locked):
    ...

最后,closing(object) 函数返回 object,以便它可以绑定到变量,并在块的末尾调用 object.close。:

import urllib, sys
from contextlib import closing

with closing(urllib.urlopen('http://www.yahoo.com')) as f:
    for line in f:
        sys.stdout.write(line)

参见

PEP 343 - "with" 语句

PEP由Guido van Rossum和Nick Coghlan编写;由Mike Bland、Guido van Rossum和Neal Norwitz实现。PEP展示了为'with'语句生成的代码,这对于学习该语句的工作原理很有帮助。

contextlib 模块的文档。

PEP 352: 异常作为新型的类

异常类现在可以是新式类,而不仅仅是经典类,内置的 Exception 类和所有标准内置异常(NameErrorValueError 等)现在都是新式类。

异常的继承层次结构已经稍微重新排列了一下。在2.5中,继承关系如下:

BaseException       # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
   |- (all other current built-in exceptions)

这种重新排列是因为人们通常希望捕获所有表示程序错误的异常。然而,KeyboardInterruptSystemExit 并不是错误,它们通常表示用户执行了明确的操作,例如按下 Control-C 或代码调用 sys.exit()。一个裸露的 except: 会捕获所有异常,因此通常需要列出 KeyboardInterruptSystemExit 以重新抛出它们。通常的模式是:

try:
    ...
except (KeyboardInterrupt, SystemExit):
    raise
except:
    # 记录错误...
    # 继续运行程序...

在 Python 2.5 中,你现在可以写 except Exception 来达到同样的效果,捕获所有通常表示错误的异常,但不包括 KeyboardInterruptSystemExit。与之前的版本一样,裸露的 except: 仍然会捕获所有异常。

Python 3.0 的目标要求任何作为异常抛出的类都必须从 BaseExceptionBaseException 的子类派生,未来 Python 2.x 系列的版本可能会开始强制执行这一约束。因此,我建议你现在就开始让你的所有异常类从 Exception 派生。有人建议在 Python 3.0 中移除裸露的 except: 形式,但 Guido van Rossum 还未决定是否这样做。

在 Python 2.5 中,将字符串作为异常抛出,如 raise "Error occurred",已被弃用,并会触发警告。目标是在几个版本后能够移除字符串异常功能。

参见

PEP 352 - 异常所需的超类

PEP 由 Brett Cannon 和 Guido van Rossum 撰写,由 Brett Cannon 实现。

PEP 353: 使用ssize_t作为索引类型

对 Python 的 C API 进行了广泛的更改,使用新的 Py_ssize_t 类型定义代替 int,这将允许解释器在 64 位平台上处理更多数据。这一更改不影响 Python 在 32 位平台上的能力。

Python解释器的各个部分使用C语言的 int 类型来存储大小或计数;例如,列表或元组中的项目数量存储在一个 int 中。大多数64位平台的C编译器仍然将 int 定义为32位类型,这意味着列表最多只能容纳 2**31 - 1 = 2147483647个项目。(实际上,64位C编译器可以使用几种不同的编程模型——参见 https://unix.org/version2/whatsnew/lp64_wp.html 进行讨论——但最常用的模型将 int 保留为32位。)

在32位平台上,2147483647个项目的限制实际上并不重要,因为在达到长度限制之前你就会耗尽内存。每个列表项需要为指针分配空间,指针为4字节,再加上表示该项的 PyObject 所需的空间。2147483647*4已经超过了32位地址空间所能容纳的字节数。

然而,在64位平台上,可以寻址这么多的内存。这么大列表的指针只需要16 GiB的空间,因此Python程序员可能会构造如此大的列表,这是合理的。因此,Python解释器必须改为使用某种不同于 int 的类型,并且在64位平台上这将是一个64位类型。这一变更将在64位机器上引起不兼容,因此现在进行过渡被认为是值得的,因为64位用户数量仍然相对较少。(在5年或10年后,我们可能 在使用64位机器,届时过渡会更加痛苦。)

这一变更对C扩展模块的作者影响最大。Python字符串和容器类型(如列表和元组)现在使用 Py_ssize_t 来存储其大小。诸如 PyList_Size() 之类的函数现在返回 Py_ssize_t。因此,扩展模块中的代码可能需要将一些变量改为 Py_ssize_t

The PyArg_ParseTuple() and Py_BuildValue() functions have a new conversion code, n, for Py_ssize_t. PyArg_ParseTuple()'s s# and t# still output int by default, but you can define the macro PY_SSIZE_T_CLEAN before including Python.h to make them return Py_ssize_t.

PEP 353 中有一节关于转换指南的内容,扩展作者应阅读以了解如何支持64位平台。

参见

PEP 353 - 使用ssize_t作为索引类型

PEP 由 Martin von Löwis 撰写并实现。

PEP 357: '__index__' 方法

The NumPy developers had a problem that could only be solved by adding a new special method, __index__(). When using slice notation, as in [start:stop:step], the values of the start, stop, and step indexes must all be either integers or long integers. NumPy defines a variety of specialized integer types corresponding to unsigned and signed integers of 8, 16, 32, and 64 bits, but there was no way to signal that these types could be used as slice indexes.

Slicing can't just use the existing __int__() method because that method is also used to implement coercion to integers. If slicing used __int__(), floating-point numbers would also become legal slice indexes and that's clearly an undesirable behaviour.

Instead, a new special method called __index__() was added. It takes no arguments and returns an integer giving the slice index to use. For example:

class C:
    def __index__ (self):
        return self.value

返回值必须是 Python 整数或长整数。解释器将检查返回的类型是否正确,如果不满足此要求,将引发 TypeError

A corresponding nb_index slot was added to the C-level PyNumberMethods structure to let C extensions implement this protocol. PyNumber_Index(obj) can be used in extension code to call the __index__() function and retrieve its result.

参见

PEP 357 - 允许将任何对象用于切片

PEP 由 Travis Oliphant 撰写并实现。

其他语言特性修改

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

  • The dict type has a new hook for letting subclasses provide a default value when a key isn't contained in the dictionary. When a key isn't found, the dictionary's __missing__(key) method will be called. This hook is used to implement the new defaultdict class in the collections module. The following example defines a dictionary that returns zero for any missing key:

    class zerodict (dict):
        def __missing__ (self, key):
            return 0
    
    d = zerodict({1:1, 2:2})
    print d[1], d[2]   # 输出 1, 2
    print d[3], d[4]   # 输出 0, 0
    
  • 8位字符串和Unicode字符串都新增了 partition(sep)rpartition(sep) 方法,简化了常见的用例。

    find(S) 方法通常用于获取一个索引,然后使用该索引来切片字符串,获取分隔符之前和之后的部分。partition(sep) 将这种模式浓缩为单个方法调用,返回一个包含分隔符之前子字符串、分隔符本身和分隔符之后子字符串的3元组。如果找不到分隔符,元组的第一个元素是整个字符串,其他两个元素为空。rpartition(sep) 也返回一个3元组,但从字符串末尾开始搜索;r 代表 'reverse'。

    示例如下:

    >>> ('http://www.pyth.onl').partition('://')
    ('http', '://', 'www.pyth.onl')
    >>> ('file:/usr/share/doc/index.html').partition('://')
    ('file:/usr/share/doc/index.html', '', '')
    >>> (u'Subject: a quick question').partition(':')
    (u'Subject', u':', u' a quick question')
    >>> 'www.pyth.onl'.rpartition('.')
    ('www.python', '.', 'org')
    >>> 'www.pyth.onl'.rpartition(':')
    ('', '', 'www.pyth.onl')
    

    (由 Fredrik Lundh 在 Raymond Hettinger 的建议下实现。)

  • The startswith() and endswith() methods of string types now accept tuples of strings to check for.

    def is_image_file (filename):
        return filename.endswith(('.gif', '.jpg', '.tiff'))
    

    (由 Georg Brandl 实现,基于 Tom Lynn 的建议。)

  • The min() and max() built-in functions gained a key keyword parameter analogous to the key argument for sort(). This parameter supplies a function that takes a single argument and is called for every value in the list; min()/max() will return the element with the smallest/largest return value from this function. For example, to find the longest string in a list, you can do:

    L = ['medium', 'longest', 'short']
    # 打印 'longest'
    print max(L, key=len)
    # 打印 'short',因为在字典序上 'short' 的值最大
    print max(L)
    

    (由 Steven Bethard 和 Raymond Hettinger 贡献。)

  • 两个新的内置函数,any()all(),用于评估迭代器中是否包含任何真值或假值。any() 如果迭代器返回的任何值为真,则返回 True;否则返回 Falseall() 只有当迭代器返回的所有值都为真时,才返回 True。(由 Guido van Rossum 建议,Raymond Hettinger 实现。)

  • The result of a class's __hash__() method can now be either a long integer or a regular integer. If a long integer is returned, the hash of that value is taken. In earlier versions the hash value was required to be a regular integer, but in 2.5 the id() built-in was changed to always return non-negative numbers, and users often seem to use id(self) in __hash__() methods (though this is discouraged).

  • ASCII 现在是模块的默认编码。如果模块包含带有 8 位字符的字符串字面量但没有编码声明,则会引发语法错误。在 Python 2.4 中,这会触发警告,而不是语法错误。参见 PEP 263 了解如何声明模块的编码;例如,你可以在源文件顶部附近添加如下行:

    # -*- coding: latin1 -*-
    
  • 一个新的警告,UnicodeWarning,在你尝试比较一个 Unicode 字符串和一个无法使用默认 ASCII 编码转换为 Unicode 的 8 位字符串时触发。比较的结果为假:

    >>> chr(128) == unichr(128)   # 无法将 chr(128) 转换为 Unicode
    __main__:1: UnicodeWarning: Unicode 等值比较失败
      无法将两个参数都转换为 Unicode - 解释为不等
    False
    >>> chr(127) == unichr(127)   # chr(127) 可以转换
    True
    

    以前这会引发一个 UnicodeDecodeError 异常,但在2.5版本中,这可能会导致在访问字典时出现令人困惑的问题。如果你查找 unichr(128)chr(128) 被用作键,你会得到一个 UnicodeDecodeError 异常。2.5版本中的其他更改导致这个异常被抛出,而不是被实现字典的 dictobject.c 中的代码抑制。

    对于这种比较引发异常是严格正确的,但这个更改可能会破坏代码,所以引入了 UnicodeWarning

    (由 Marc-André Lemburg 实现。)

  • Python程序员有时会犯的一个错误是忘记在包目录中包含一个 __init__.py 模块。调试这个错误可能会令人困惑,通常需要使用 -v 开关运行Python来记录所有搜索的路径。在Python 2.5中,当导入操作本应将一个目录作为包但未找到 __init__.py 时,会触发新的 ImportWarning 警告。默认情况下,这个警告被静默忽略;在运行Python可执行文件时提供 -Wd 选项来显示警告消息。(由 Thomas Wouters 实现。)

  • 类定义中的基类列表现在可以是空的。例如,以下现在是合法的:

    class C():
        pass
    

    (由 Brett Cannon 实现。)

交互解释器变更

在交互式解释器中,quitexit 长期以来一直是字符串,以便新用户在尝试退出时得到一些有帮助的消息:

>>> quit
'使用Ctrl-D(即EOF)退出。'

在Python 2.5中,quitexit 现在是对象,它们仍然产生自己的字符串表示,但也是可调用的。新手尝试 quit()exit() 现在将如他们所期望的那样退出解释器。(由Georg Brandl实现。)

Python可执行文件现在接受标准的长选项 --help--version;在Windows上,它还接受 /? 选项来显示帮助消息。(由 Georg Brandl 实现。)

性能优化

多项优化是在2006年5月21日至28日在冰岛雷克雅未克举行的NeedForSpeed冲刺活动中开发的。该冲刺活动专注于提升CPython实现的速度,由EWT LLC资助,并得到了CCP Games的本地支持。在此冲刺中添加的优化在以下列表中特别标注。

  • 在Python 2.4中引入时,内置的 setfrozenset 类型是基于Python的字典类型构建的。在2.5中,内部数据结构已为实现集合进行了定制,因此集合将使用少三分之一的内存,并且速度有所提高。(由 Raymond Hettinger 实现。)

  • 一些Unicode操作的速度,如查找子字符串、字符串分割以及字符映射的编码和解码,已得到提升。(子字符串搜索和分割改进由Fredrik Lundh和Andrew Dalke在NeedForSpeed冲刺中添加。字符映射由Walter Dörwald和Martin von Löwis改进。)

  • long(str, base) 函数现在在处理长数字字符串时更快,因为计算的中间结果更少。峰值出现在约 800 到 1000 位的字符串上,此时函数速度提升了 6 倍。(由 Alan McIntyre 贡献,并在 NeedForSpeed 冲刺中提交。)

  • It's now illegal to mix iterating over a file with for line in file and calling the file object's read()/readline()/readlines() methods. Iteration uses an internal buffer and the read*() methods don't use that buffer. Instead they would return the data following the buffer, causing the data to appear out of order. Mixing iteration and these methods will now trigger a ValueError from the read*() method. (Implemented by Thomas Wouters.)

  • struct 模块现在将结构格式字符串编译成内部表示并缓存此表示,从而提高了20%的速度。(由Bob Ippolito在NeedForSpeed冲刺中贡献。)

  • re 模块通过切换到 Python 的分配器函数而不是系统的 malloc()free(),获得了 1% 到 2% 的速度提升。(由 Jack Diederich 在 NeedForSpeed sprint 中贡献。)

  • 代码生成器的窥孔优化器现在可以在表达式中执行简单的常量折叠。如果你写类似 a = 2+3 的代码,代码生成器将进行算术运算并生成对应于 a = 5 的代码。(由 Raymond Hettinger 提议并实现。)

  • 函数调用现在更快了,因为代码对象现在将最近完成的帧(一个“僵尸帧”)保存在代码对象的内部字段中,下次调用代码对象时重用它。(原始补丁由 Michael Hudson 提供,由 Armin Rigo 和 Richard Jones 修改;在 NeedForSpeed sprint 中提交。)帧对象也稍微变小了,这可能会改善缓存局部性并略微减少内存使用。(由 Neal Norwitz 贡献。)

  • Python 的内置异常现在都是新式类,这一改变显著加快了实例化速度。因此,Python 2.5 中的异常处理比 2.4 快约 30%。(由 Richard Jones、Georg Brandl 和 Sean Reifschneider 在 NeedForSpeed sprint 中贡献。)

  • Importing now caches the paths tried, recording whether they exist or not so that the interpreter makes fewer open() and stat() calls on startup. (Contributed by Martin von Löwis and Georg Brandl.)

新增,改进和删除的模块

Python 2.5 中的标准库收到了许多增强和 bug 修复。以下是按模块名称字母顺序排序的最显著变化的部分列表。查阅源树中的 Misc/NEWS 文件以获取更完整的变化列表,或通过 SVN 日志查看所有详细信息。

  • audioop 模块现在支持 a-LAW 编码,并且 u-LAW 编码的代码已得到改进。(由 Lars Immisch 贡献。)

  • The codecs module gained support for incremental codecs. The codecs.lookup() function now returns a CodecInfo instance instead of a tuple. CodecInfo instances behave like a 4-tuple to preserve backward compatibility but also have the attributes encode, decode, incrementalencoder, incrementaldecoder, streamwriter, and streamreader. Incremental codecs can receive input and produce output in multiple chunks; the output is the same as if the entire input was fed to the non-incremental codec. See the codecs module documentation for details. (Designed and implemented by Walter Dörwald.)

  • The collections module gained a new type, defaultdict, that subclasses the standard dict type. The new type mostly behaves like a dictionary but constructs a default value when a key isn't present, automatically adding it to the dictionary for the requested key value.

    The first argument to defaultdict's constructor is a factory function that gets called whenever a key is requested but not found. This factory function receives no arguments, so you can use built-in type constructors such as list() or int(). For example, you can make an index of words based on their initial letter like this:

    words = """Nel mezzo del cammin di nostra vita
    mi ritrovai per una selva oscura
    che la diritta via era smarrita""".lower().split()
    
    index = defaultdict(list)
    
    for w in words:
        init_letter = w[0]
        index[init_letter].append(w)
    

    打印 index 导致以下输出:

    defaultdict(<type 'list'>, {'c': ['cammin', 'che'], 'e': ['era'],
            'd': ['del', 'di', 'diritta'], 'm': ['mezzo', 'mi'],
            'l': ['la'], 'o': ['oscura'], 'n': ['nel', 'nostra'],
            'p': ['per'], 's': ['selva', 'smarrita'],
            'r': ['ritrovai'], 'u': ['una'], 'v': ['vita', 'via']})
    

    (由 Guido van Rossum 贡献。)

  • The deque double-ended queue type supplied by the collections module now has a remove(value) method that removes the first occurrence of value in the queue, raising ValueError if the value isn't found. (Contributed by Raymond Hettinger.)

  • 新模块:contextlib 模块包含用于新 'with' 语句的辅助函数。更多信息请参见 contextlib 模块 部分。

  • 新模块:cProfile 模块是现有 profile 模块的 C 语言实现,具有更低的开销。该模块的接口与 profile 相同:你可以通过运行 cProfile.run('main()') 来分析函数,可以将分析数据保存到文件等。目前尚不清楚 Hotshot 分析器(同样用 C 语言编写,但接口与 profile 模块不匹配)是否会在 Python 的未来版本中继续维护。(由 Armin Rigo 贡献。)

    Also, the pstats module for analyzing the data measured by the profiler now supports directing the output to any file object by supplying a stream argument to the Stats constructor. (Contributed by Skip Montanaro.)

  • The csv module, which parses files in comma-separated value format, received several enhancements and a number of bugfixes. You can now set the maximum size in bytes of a field by calling the csv.field_size_limit(new_limit) function; omitting the new_limit argument will return the currently set limit. The reader class now has a line_num attribute that counts the number of physical lines read from the source; records can span multiple physical lines, so line_num is not the same as the number of records read.

    CSV解析器现在对多行引号字段更为严格。之前,如果在引号字段内一行结束而没有终止换行符,会在返回的字段中插入一个换行符。这种行为在读取字段内包含回车字符的文件时会导致问题,因此代码已更改,返回字段时不插入换行符。因此,如果字段内嵌入的换行符很重要,输入应在保持换行符的方式下拆分成行。

    (由Skip Montanaro 和 Andrew McNamara 贡献。)

  • datetime 模块中的 datetime 类现在有一个 strptime(string, format) 方法用于解析日期字符串,由Josh Spoerri贡献。它使用与 time.strptime()time.strftime() 相同的格式字符:

    import datetime as dt
    
    ts = dt.datetime.strptime('10:13:15 2006-03-07',
                              '%H:%M:%S %Y-%m-%d')
    
  • The difflib.SequenceMatcher.get_matching_blocks() method in the difflib module now guarantees to return a minimal list of blocks describing matching subsequences. Previously, the algorithm would occasionally break a block of matching elements into two list entries. (Enhancement by Tim Peters.)

  • doctest 模块增加了一个 SKIP 选项,用于完全跳过示例的执行。这是为了那些作为读者使用示例的代码片段,而不是实际的测试用例。

    An encoding parameter was added to the testfile() function and the DocFileSuite class to specify the file's encoding. This makes it easier to use non-ASCII characters in tests contained within a docstring. (Contributed by Bjorn Tillenius.)

  • email 包已经升级到 4.0版 (由 Barry Warsaw 贡献)

  • The fileinput module was made more flexible. Unicode filenames are now supported, and a mode parameter that defaults to "r" was added to the input() function to allow opening files in binary or universal newlines mode. Another new parameter, openhook, lets you use a function other than open() to open the input files. Once you're iterating over the set of files, the FileInput object's new fileno() returns the file descriptor for the currently opened file. (Contributed by Georg Brandl.)

  • In the gc module, the new get_count() function returns a 3-tuple containing the current collection counts for the three GC generations. This is accounting information for the garbage collector; when these counts reach a specified threshold, a garbage collection sweep will be made. The existing gc.collect() function now takes an optional generation argument of 0, 1, or 2 to specify which generation to collect. (Contributed by Barry Warsaw.)

  • The nsmallest() and nlargest() functions in the heapq module now support a key keyword parameter similar to the one provided by the min()/max() functions and the sort() methods. For example:

    >>> import heapq
    >>> L = ["short", 'medium', 'longest', 'longer still']
    >>> heapq.nsmallest(2, L)  # 按字典序返回两个最低的元素
    ['longer still', 'longest']
    >>> heapq.nsmallest(2, L, key=len)   # 返回两个最短的元素
    ['short', 'medium']
    

    (由 Raymond Hettinger 贡献。)

  • itertools.islice() 函数现在接受 None 作为 start 和 step 参数。这使得它与切片对象的属性更加兼容,因此你现在可以写出以下代码:

    s = slice(5)     # 创建切片对象
    itertools.islice(iterable, s.start, s.stop, s.step)
    

    (由 Raymond Hettinger 贡献。)

  • The format() function in the locale module has been modified and two new functions were added, format_string() and currency().

    format() 函数的 val 参数以前可以是字符串,只要不超过一个 %char 指定符;现在该参数必须正好是一个 %char 指定符,且周围没有文本。还添加了一个可选的 monetary 参数,如果为 True,将使用区域设置的规则来格式化货币,在每三位数字之间放置分隔符。

    To format strings with multiple %char specifiers, use the new format_string() function that works like format() but also supports mixing %char specifiers with arbitrary text.

    A new currency() function was also added that formats a number according to the current locale's settings.

    (由Georg Brandl 贡献。)

  • The mailbox module underwent a massive rewrite to add the capability to modify mailboxes in addition to reading them. A new set of classes that include mbox, MH, and Maildir are used to read mailboxes, and have an add(message) method to add messages, remove(key) to remove messages, and lock()/unlock() to lock/unlock the mailbox. The following example converts a maildir-format mailbox into an mbox-format one:

    import mailbox
    
    # 'factory=None' 使用 email.Message.Message 作为表示
    # 单个消息的类。
    src = mailbox.Maildir('maildir', factory=None)
    dest = mailbox.mbox('/tmp/mbox')
    
    for msg in src:
        dest.add(msg)
    

    (由 Gregory K. Johnson 贡献。资金由 Google 2005 年夏季代码提供。)

  • 新模块:msilib 模块允许创建 Microsoft Installer .msi 文件和 CAB 文件。还包括一些支持读取 .msi 数据库的功能。(由 Martin von Löwis 贡献。)

  • nis 模块现在支持通过向 nis.match()nis.maps() 函数提供 domain 参数来访问系统默认域以外的其他域。(由 Ben Bell 贡献。)

  • The operator module's itemgetter() and attrgetter() functions now support multiple fields. A call such as operator.attrgetter('a', 'b') will return a function that retrieves the a and b attributes. Combining this new feature with the sort() method's key parameter lets you easily sort lists using multiple fields. (Contributed by Raymond Hettinger.)

  • The optparse module was updated to version 1.5.1 of the Optik library. The OptionParser class gained an epilog attribute, a string that will be printed after the help message, and a destroy() method to break reference cycles created by the object. (Contributed by Greg Ward.)

  • The os module underwent several changes. The stat_float_times variable now defaults to true, meaning that os.stat() will now return time values as floats. (This doesn't necessarily mean that os.stat() will return times that are precise to fractions of a second; not all systems support such precision.)

    添加了名为 os.SEEK_SETos.SEEK_CURos.SEEK_END 的常量;这些是 os.lseek() 函数的参数。用于锁定的两个新常量是 os.O_SHLOCKos.O_EXLOCK

    Two new functions, wait3() and wait4(), were added. They're similar the waitpid() function which waits for a child process to exit and returns a tuple of the process ID and its exit status, but wait3() and wait4() return additional information. wait3() doesn't take a process ID as input, so it waits for any child process to exit and returns a 3-tuple of process-id, exit-status, resource-usage as returned from the resource.getrusage() function. wait4(pid) does take a process ID. (Contributed by Chad J. Schroeder.)

    On FreeBSD, the os.stat() function now returns times with nanosecond resolution, and the returned object now has st_gen and st_birthtime. The st_flags attribute is also available, if the platform supports it. (Contributed by Antti Louko and Diego Pettenò.)

  • pdb 模块提供的 Python 调试器现在可以存储一系列命令,当达到断点并停止执行时执行这些命令。一旦创建了断点 #1,输入 commands 1 并输入一系列要执行的命令,最后用 end 结束列表。命令列表可以包括恢复执行的命令,如 continuenext。(由 Grégoire Dooms 贡献。)

  • picklecPickle 模块不再接受 __reduce__() 方法返回的 None 值;该方法必须返回一个参数元组。在 Python 2.4 中已弃用返回 None 的能力,因此这完成了该特性的移除。

  • pkgutil 模块包含用于查找包的各种实用函数,已增强以支持 PEP 302 的导入钩子,现在也适用于存储在 ZIP 格式归档中的包。(由 Phillip J. Eby 贡献。)

  • Marc-André Lemburg 开发的 pybench 基准测试套件现在包含在 Tools/pybench 目录中。pybench 套件是对常用的 pystone.py 程序的改进,因为 pybench 提供了对解释器速度的更详细测量。它计时特定操作,如函数调用、元组切片、方法查找和数值操作,而不是执行许多不同操作并将结果简化为一个数字,如 pystone.py 所做的那样。

  • The pyexpat module now uses version 2.0 of the Expat parser. (Contributed by Trent Mick.)

  • The Queue class provided by the queue module gained two new methods. join() blocks until all items in the queue have been retrieved and all processing work on the items have been completed. Worker threads call the other new method, task_done(), to signal that processing for an item has been completed. (Contributed by Raymond Hettinger.)

  • The old regex and regsub modules, which have been deprecated ever since Python 2.0, have finally been deleted. Other deleted modules: statcache, tzparse, whrandom.

  • Also deleted: the lib-old directory, which includes ancient modules such as dircmp and ni, was removed. lib-old wasn't on the default sys.path, so unless your programs explicitly added the directory to sys.path, this removal shouldn't affect your code.

  • rlcompleter 模块不再依赖于导入 readline 模块,因此现在可以在非 Unix 平台上工作。(由 Robert Kiendl 提供的补丁。)

  • The SimpleXMLRPCServer and DocXMLRPCServer classes now have a rpc_paths attribute that constrains XML-RPC operations to a limited set of URL paths; the default is to allow only '/' and '/RPC2'. Setting rpc_paths to None or an empty tuple disables this path checking.

  • The socket module now supports AF_NETLINK sockets on Linux, thanks to a patch from Philippe Biondi. Netlink sockets are a Linux-specific mechanism for communications between a user-space process and kernel code; an introductory article about them is at https://www.linuxjournal.com/article/7356. In Python code, netlink addresses are represented as a tuple of 2 integers, (pid, group_mask).

    套接字对象上的两个新方法 recv_into(buffer)recvfrom_into(buffer) 将接收到的数据存储在支持缓冲协议的对象中,而不是将数据作为字符串返回。这意味着你可以直接将数据放入数组或内存映射文件中。

    Socket objects also gained getfamily(), gettype(), and getproto() accessor methods to retrieve the family, type, and protocol values for the socket.

  • 新模块:spwd 模块提供了在支持影子密码的系统上访问影子密码数据库的函数。

  • The struct is now faster because it compiles format strings into Struct objects with pack() and unpack() methods. This is similar to how the re module lets you create compiled regular expression objects. You can still use the module-level pack() and unpack() functions; they'll create Struct objects and cache them. Or you can use Struct instances directly:

    s = struct.Struct('ih3s')
    
    data = s.pack(1972, 187, 'abc')
    year, number, name = s.unpack(data)
    

    你还可以使用 pack_into(buffer, offset, v1, v2, ...)unpack_from(buffer, offset) 方法直接将数据打包和解包到缓冲对象中。这允许你直接将数据存储到数组或内存映射文件中。

    (Struct objects were implemented by Bob Ippolito at the NeedForSpeed sprint. Support for buffer objects was added by Martin Blais, also at the NeedForSpeed sprint.)

  • Python 开发者在 2.5 开发过程中从 CVS 切换到 Subversion。关于确切构建版本的信息可通过 sys.subversion 变量获取,这是一个包含 (解释器名称, 分支名称, 版本范围) 的 3 元组。例如,在撰写本文时,我的 2.5 版本报告为 ('CPython', 'trunk', '45313:45315')

    此信息也可通过 Py_GetBuildInfo() 函数供 C 扩展使用,该函数返回一个构建信息字符串,例如:"trunk:45355:45356M, Apr 13 2006, 07:42:19"。 (由 Barry Warsaw 贡献。)

  • 另一个新函数 sys._current_frames() 返回所有运行线程的当前堆栈帧,作为字典映射,其中线程标识符映射到在该函数调用时该线程中当前活动的最顶层堆栈帧。 (由 Tim Peters 贡献。)

  • The TarFile class in the tarfile module now has an extractall() method that extracts all members from the archive into the current working directory. It's also possible to set a different directory as the extraction target, and to unpack only a subset of the archive's members.

    在流模式下打开的 tarfile 的压缩类型现在可以通过模式 'r|*' 自动检测。 (由 Lars Gustäbel 贡献。)

  • threading 模块现在允许你设置创建新线程时使用的堆栈大小。stack_size([*size*]) 函数返回当前配置的堆栈大小,提供可选的 size 参数可以设置新值。并非所有平台都支持更改堆栈大小,但 Windows、POSIX 线程和 OS/2 都支持。 (由 Andrew MacIntyre 贡献。)

  • unicodedata 模块已更新为使用 Unicode 字符数据库版本 4.1.0。某些规范要求版本 3.2.0,因此它仍然作为 unicodedata.ucd_3_2_0 可用。

  • New module: the uuid module generates universally unique identifiers (UUIDs) according to RFC 4122. The RFC defines several different UUID versions that are generated from a starting string, from system properties, or purely randomly. This module contains a UUID class and functions named uuid1(), uuid3(), uuid4(), and uuid5() to generate different versions of UUID. (Version 2 UUIDs are not specified in RFC 4122 and are not supported by this module.)

    >>> import uuid
    >>> # 基于主机 ID 和当前时间生成一个 UUID
    >>> uuid.uuid1()
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
    
    >>> # 使用命名空间 UUID 和名称的 MD5 哈希生成一个 UUID
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'pyth.onl')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
    
    >>> # 生成一个随机 UUID
    >>> uuid.uuid4()
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
    
    >>> # 使用命名空间 UUID 和名称的 SHA-1 哈希生成一个 UUID
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'pyth.onl')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
    

    (由 Ka-Ping Yee 贡献。)

  • The weakref module's WeakKeyDictionary and WeakValueDictionary types gained new methods for iterating over the weak references contained in the dictionary. iterkeyrefs() and keyrefs() methods were added to WeakKeyDictionary, and itervaluerefs() and valuerefs() were added to WeakValueDictionary. (Contributed by Fred L. Drake, Jr.)

  • The webbrowser module received a number of enhancements. It's now usable as a script with python -m webbrowser, taking a URL as the argument; there are a number of switches to control the behaviour (-n for a new browser window, -t for a new tab). New module-level functions, open_new() and open_new_tab(), were added to support this. The module's open() function supports an additional feature, an autoraise parameter that signals whether to raise the open window when possible. A number of additional browsers were added to the supported list such as Firefox, Opera, Konqueror, and elinks. (Contributed by Oleg Broytmann and Georg Brandl.)

  • xmlrpclib 模块现在支持将 XML-RPC 日期类型返回为 datetime 对象。向 loads() 函数或 Unmarshaller 类提供 use_datetime=True 参数以启用此功能。(由 Skip Montanaro 贡献。)

  • zipfile 模块现在支持 ZIP64 版本的格式,这意味着 .zip 归档文件现在可以大于 4 GiB,并且可以包含大于 4 GiB 的单个文件。(由 Ronald Oussoren 贡献。)

  • The zlib module's Compress and Decompress objects now support a copy() method that makes a copy of the object's internal state and returns a new Compress or Decompress object. (Contributed by Chris AtLee.)

ctypes 包

由 Thomas Heller 编写的 ctypes 包已被添加到标准库中。ctypes 允许你调用共享库或 DLL 中的任意函数。长期用户可能记得 dl 模块,它提供了加载共享库和调用其中函数的功能。ctypes 包要高级得多。

To load a shared library or DLL, you must create an instance of the CDLL class and provide the name or path of the shared library or DLL. Once that's done, you can call arbitrary functions by accessing them as attributes of the CDLL object.

import ctypes

libc = ctypes.CDLL('libc.so.6')
result = libc.printf("Line of output\n")

Type constructors for the various C types are provided: c_int(), c_float(), c_double(), c_char_p() (equivalent to char*), and so forth. Unlike Python's types, the C versions are all mutable; you can assign to their value attribute to change the wrapped value. Python integers and strings will be automatically converted to the corresponding C types, but for other types you must call the correct type constructor. (And I mean must; getting it wrong will often result in the interpreter crashing with a segmentation fault.)

You shouldn't use c_char_p() with a Python string when the C function will be modifying the memory area, because Python strings are supposed to be immutable; breaking this rule will cause puzzling bugs. When you need a modifiable memory area, use create_string_buffer():

s = "this is a string"
buf = ctypes.create_string_buffer(s)
libc.strfry(buf)

C functions are assumed to return integers, but you can set the restype attribute of the function object to change this:

>>> libc.atof('2.71828')
-1783957616
>>> libc.atof.restype = ctypes.c_double
>>> libc.atof('2.71828')
2.71828

ctypes 还为Python的C API提供了一个包装器,即 ctypes.pythonapi 对象。这个对象在调用函数之前 释放全局解释器锁,因为调用解释器代码时必须持有该锁。还有一个 py_object 类型构造器,它将创建一个 PyObject* 指针。一个简单的用法:

import ctypes

d = {}
ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d),
          ctypes.py_object("abc"),  ctypes.py_object(1))
# d 现在是 {'abc', 1}。

不要忘记使用 py_object();如果省略它,你最终会遇到段错误。

ctypes 已经存在一段时间了,但人们仍然编写和分发手工编码的扩展模块,因为你不能依赖 ctypes 的存在。也许开发者现在会开始编写通过 ctypes 访问库的 Python 包装器,而不是扩展模块,因为 ctypes 已包含在核心 Python 中。

参见

https://web.archive.org/web/20180410025338/http://starship.python.net/crew/theller/ctypes/

预标准库 ctypes 的网页,包含教程、参考和常见问题解答。

ctypes 模块的文档。

ElementTree 包

A subset of Fredrik Lundh's ElementTree library for processing XML has been added to the standard library as xml.etree. The available modules are ElementTree, ElementPath, and ElementInclude from ElementTree 1.2.6. The cElementTree accelerator module is also included.

本节的剩余部分将提供使用 ElementTree 的简要说明。 要获取 ElementTree 的完整文档可访问 https://web.archive.org/web/20201124024954/http://effbot.org/zone/element-index.htm

ElementTree represents an XML document as a tree of element nodes. The text content of the document is stored as the text and tail attributes of (This is one of the major differences between ElementTree and the Document Object Model; in the DOM there are many different types of node, including TextNode.)

The most commonly used parsing function is parse(), that takes either a string (assumed to contain a filename) or a file-like object and returns an ElementTree instance:

from xml.etree import ElementTree as ET

tree = ET.parse('ex-1.xml')

feed = urllib.urlopen(
          'http://planet.pyth.onl/rss10.xml')
tree = ET.parse(feed)

Once you have an ElementTree instance, you can call its getroot() method to get the root Element node.

There's also an XML() function that takes a string literal and returns an Element node (not an ElementTree). This function provides a tidy way to incorporate XML fragments, approaching the convenience of an XML literal:

svg = ET.XML("""<svg width="10px" version="1.0">
             </svg>""")
svg.set('height', '320px')
svg.append(elem1)

每个 XML 元素都支持一些类似字典和类似列表的访问方法。类似字典的操作用于访问属性值,而类似列表的操作用于访问子节点。

运算

结果:

elem[n]

返回第n个子元素。

elem[m:n]

返回第m至第n个子元素的列表。

len(elem)

返回子元素的个数。

list(elem)

返回子元素的列表。

elem.append(elem2)

elem2 添加为子级。

elem.insert(index, elem2)

在指定位置插入 elem2

del elem[n]

删除第n个子元素。

elem.keys()

返回属性名称的列表。

elem.get(name)

返回 name 属性的值。

elem.set(name, value)

name 属性设置新值。

elem.attrib

检索包含属性的字典。

del elem.attrib[name]

删除 元素 name 的属性。

Comments and processing instructions are also represented as Element nodes. To check if a node is a comment or processing instructions:

if elem.tag is ET.Comment:
    ...
elif elem.tag is ET.ProcessingInstruction:
    ...

To generate XML output, you should call the xml.etree.ElementTree.ElementTree.write() method. Like parse(), it can take either a string or a file-like object:

# 编码为 US-ASCII
tree.write('output.xml')

# 编码为 UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')

(注意:输出的默认编码是 ASCII。对于一般的 XML 工作,其中元素的名称可能包含任意的 Unicode 字符,ASCII 不是一个非常有用的编码,因为它会在元素名称包含任何值大于 127 的字符时引发异常。因此,最好指定一个不同的编码,如 UTF-8,它可以处理任何 Unicode 字符。)

本节仅对 ElementTree 接口进行了部分描述。请阅读包的官方文档以获取更多详细信息。

hashlib 包

由 Gregory P. Smith 编写的一个新的 hashlib 模块已被添加,以替换 md5sha 模块。hashlib 增加了对额外安全哈希(SHA-224、SHA-256、SHA-384 和 SHA-512)的支持。在可用的情况下,该模块使用 OpenSSL 以实现快速的平台优化算法实现。

旧的 md5sha 模块仍然存在,作为 hashlib 的包装器以保持向后兼容性。新模块的接口与旧模块非常接近,但不完全相同。最显著的区别是用于创建新哈希对象的构造函数命名不同。:

# 旧版本
h = md5.md5()
h = md5.new()

# 新版本
h = hashlib.md5()

# 旧版本
h = sha.sha()
h = sha.new()

# 新版本
h = hashlib.sha1()

# 之前不可用的哈希
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()

# 备选形式
h = hashlib.new('md5')          # 以字符串形式提供算法

Once a hash object has been created, its methods are the same as before: update(string) hashes the specified string into the current digest state, digest() and hexdigest() return the digest value as a binary string or a string of hex digits, and copy() returns a new hashing object with the same digest state.

参见

hashlib 模块的文档。

sqlite3 包

pysqlite 模块(https://www.pysqlite.org),作为 SQLite 嵌入式数据库的包装器,已被添加到标准库中,包名为 sqlite3

SQLite 是一个C语言库,它可以提供一种轻量级的基于磁盘的数据库,这种数据库不需要独立的服务器进程,也允许需要使用一种非标准的 SQL 查询语言来访问它。一些应用程序可以使用 SQLite 作为内部数据存储。可以用它来创建一个应用程序原型,然后再迁移到更大的数据库,比如 PostgreSQL 或 Oracle。

pysqlite 由 Gerhard Häring 编写,提供了一个符合 PEP 249 描述的 DB-API 2.0 规范的 SQL 接口。

如果你自己编译 Python 源代码,请注意源代码树不包含 SQLite 代码,只包含封装模块。在编译 Python 之前,你需要安装 SQLite 库和头文件,当必要的头文件可用时,编译过程将编译模块。

To use the module, you must first create a Connection object that represents the database. Here the data will be stored in the /tmp/example file:

conn = sqlite3.connect('/tmp/example')

你也可以使用 :memory: 来创建一个内存中的数据库。

Once you have a Connection, you can create a Cursor object and call its execute() method to perform SQL commands:

c = conn.cursor()

# 创建表
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')

# 插入一行数据
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")

通常,你的 SQL 操作需要使用来自 Python 变量的值。 你不应该使用 Python 的字符串操作来组装你的查询,因为这样做是不安全的,它会使你的程序容易受到 SQL 注入攻击。

Instead, use the DB-API's parameter substitution. Put ? as a placeholder wherever you want to use a value, and then provide a tuple of values as the second argument to the cursor's execute() method. (Other database modules may use a different placeholder, such as %s or :1.) For example:

# 千万不要这样做 -- 不安全!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# 应该这样做
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)

# 更大的示例
for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
          ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00),
          ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
         ):
    c.execute('insert into stocks values (?,?,?,?,?)', t)

To retrieve data after executing a SELECT statement, you can either treat the cursor as an iterator, call the cursor's fetchone() method to retrieve a single matching row, or call fetchall() to get a list of the matching rows.

下面是一个使用迭代器形式的例子:

>>> c = conn.cursor()
>>> c.execute('select * from stocks order by price')
>>> for row in c:
...    print row
...
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0)
>>>

有关 SQLite 所支持的 SQL 方法的更多信息,请参阅 https://www.sqlite.org

参见

https://www.pysqlite.org

pysqlite 的主页。

https://www.sqlite.org

SQLite的主页;它的文档详细描述了它所支持的 SQL 方言的语法和可用的数据类型。

sqlite3 模块的文档。

PEP 249 - DB-API 2.0 规范

PEP 由 Marc-André Lemburg 撰写。

wsgiref 包

Web 服务器网关接口 (WSGI) v1.0 定义了 Web 服务器和 Python Web 应用程序之间的标准接口,并在 PEP 333 中进行了描述。wsgiref 包是 WSGI 规范的参考实现。

该软件包包含一个基本 HTTP 服务器,可运行 WSGI 应用程序;该服务器可用于调试,但不打算用于生产环境。设置服务器只需几行代码:

from wsgiref import simple_server

wsgi_app = ...

host = ''
port = 8000
httpd = simple_server.make_server(host, port, wsgi_app)
httpd.serve_forever()

参见

https://web.archive.org/web/20160331090247/http://wsgi.readthedocs.org/en/latest/

WSGI相关资源的核心网站。

PEP 333 - Python Web服务器网关接口 v1.0

PEP 由 Phillip J. Eby 撰写。

构建和 C API 的变更

针对 Python 构建过程和 C API 的变更包括:

  • Python 源代码树从 CVS 转换为 Subversion,这一复杂的迁移过程由 Martin von Löwis 监督并完美执行。该过程按 PEP 347 进行了开发。

  • Coverity 公司,一家销售名为 Prevent 的源代码分析工具的公司,提供了他们对 Python 源代码的检查结果。分析发现了大约 60 个错误,这些错误很快被修复。许多错误是引用计数问题,通常出现在错误处理代码中。详见 https://scan.coverity.com 了解统计数据。

  • C API 最大的变化来自 PEP 353,该提案修改了解释器,使其使用 Py_ssize_t 类型定义而不是 int。详见前文 PEP 353: 使用ssize_t作为索引类型 部分对此变化的讨论。

  • 字节码编译器的设计发生了很大变化,不再通过遍历解析树生成字节码。相反,解析树被转换为抽象语法树(AST),然后遍历抽象语法树来生成字节码。

    Python 代码可以通过使用内置的 compile() 函数并指定 _ast.PyCF_ONLY_AST 作为 flags 参数的值来获取 AST 对象:

    from _ast import PyCF_ONLY_AST
    ast = compile("""a=0
    for i in range(10):
        a += i
    """, "<string>", 'exec', PyCF_ONLY_AST)
    
    assignment = ast.body[0]
    for_loop = ast.body[1]
    

    No official documentation has been written for the AST code yet, but PEP 339 discusses the design. To start learning about the code, read the definition of the various AST nodes in Parser/Python.asdl. A Python script reads this file and generates a set of C structure definitions in Include/Python-ast.h. The PyParser_ASTFromString() and PyParser_ASTFromFile(), defined in Include/pythonrun.h, take Python source as input and return the root of an AST representing the contents. This AST can then be turned into a code object by PyAST_Compile(). For more information, read the source code, and then ask questions on python-dev.

    AST 代码在 Jeremy Hylton 的管理下开发,并由以下人员(按字母顺序)实现:Brett Cannon、Nick Coghlan、Grant Edwards、John Ehresman、Kurt Kaiser、Neal Norwitz、Tim Peters、Armin Rigo 和 Neil Schemenauer,以及参与 PyCon 等会议中多次 AST 短暂开发活动的参与者。

  • Evan Jones 提出的 obmalloc 补丁,最初在 PyCon DC 2005 的一次演讲中描述,已被应用。Python 2.4 在 256K 大小的区域中分配小对象,但不释放这些区域。有了这个补丁,Python 将在区域为空时释放它们。净效果是,在某些平台上,当你分配许多对象时,删除这些对象后 Python 的内存使用可能会实际减少,并且内存可能会返回给操作系统。(由 Evan Jones 实现,并由 Tim Peters 重构。)

    请注意,这一变化意味着扩展模块在分配内存时必须更加小心。Python 的 API 有许多不同的内存分配函数,它们被分组到不同的家族中。例如,PyMem_Malloc()PyMem_Realloc()PyMem_Free() 是一个用于分配原始内存的家族,而 PyObject_Malloc()PyObject_Realloc()PyObject_Free() 是另一个用于创建 Python 对象的家族。

    以前,这些不同的家族最终都归结为平台的 malloc()free() 函数。这意味着如果你搞错了,用 PyMem 函数分配内存却用 PyObject 函数释放它,也不会有问题。但随着 2.5 版对 obmalloc 的更改,这些家族现在执行不同的操作,不匹配可能会导致段错误。你应该仔细测试你的 C 扩展模块与 Python 2.5 的兼容性。

  • 内置集合类型现在拥有官方的C API。调用 PySet_New()PyFrozenSet_New() 创建新集合,使用 PySet_Add()PySet_Discard() 添加和移除元素,以及使用 PySet_Contains()PySet_Size() 检查集合的状态。(由 Raymond Hettinger 贡献。)

  • C代码现在可以通过调用 Py_GetBuildInfo() 函数获取Python解释器的确切修订信息,该函数返回一个包含构建信息的字符串,例如:"trunk:45355:45356M, Apr 13 2006, 07:42:19"。(由 Barry Warsaw 贡献。)

  • 新增两个宏用于指示当前文件所属的局部 C 函数以便能够使用更快速的调用约定。 Py_LOCAL 声明函数将返回指定 type 的值并使用快速调用限定符。 Py_LOCAL_INLINE 执行相同的操作并还将请求函数是内联的。 如果在包括 python.h 之前 PY_LOCAL_AGGRESSIVE 已被定义,则会为模块启用一组更激进的优化;你应当对结果进行基准测试以确定这些优化是否确实能使代码运行更快速。 (由 Fredrik Lundh 在 NeedForSpeed sprint 中贡献。)

  • PyErr_NewException(name, base, dict) 现在可以接受一个基类元组作为其 base 参数。(由 Georg Brandl 贡献。)

  • 用于发出警告的 PyErr_Warn() 函数现在已弃用,推荐使用 PyErr_WarnEx(category, message, stacklevel),它允许你指定此函数与调用者之间的堆栈帧数。stacklevel 为1是调用 PyErr_WarnEx() 的函数,2是之上的函数,依此类推。(由 Neal Norwitz 添加。)

  • CPython解释器仍然用C语言编写,但现在代码可以用C++编译器编译而不会出错。(由 Anthony Baxter、Martin von Löwis、Skip Montanaro 实现。)

  • PyRange_New() 函数已被移除。该函数从未被文档化,从未在核心代码中使用,并且具有危险的宽松错误检查。在极少数情况下,如果你的扩展使用了它,你可以用类似以下代码替换:

    range = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll",
                                  start, stop, step);
    

移植专属的改变

  • MacOS X (10.3 及更高版本): 模块的动态加载现在会使用 dlopen() 函数而不是 MacOS 专属的函数。

  • MacOS X:在 configure 脚本中添加了 --enable-universalsdk 开关,用于将解释器编译为通用二进制文件,能够在 PowerPC 和 Intel 处理器上运行。(由 Ronald Oussoren 贡献;bpo-2573。)

  • Windows:.dll 已不再作为扩展模块的文件名扩展名支持。现在只搜索 .pyd 作为文件名扩展名。

移植到Python 2.5

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

  • ASCII 现在是模块的默认编码。如果一个模块包含带有 8 位字符的字符串字面量但没有编码声明,现在会引发语法错误。在 Python 2.4 中,这会触发警告,而不是语法错误。

  • Previously, the gi_frame attribute of a generator was always a frame object. Because of the PEP 342 changes described in section PEP 342: 生成器的新特性, it's now possible for gi_frame to be None.

  • 新增警告 UnicodeWarning,当尝试比较一个 Unicode 字符串和一个无法使用默认 ASCII 编码转换为 Unicode 的 8 位字符串时触发。之前此类比较会引发 UnicodeDecodeError 异常。

  • 库:csv 模块现在对多行引用字段更为严格。如果你的文件中包含嵌入字段中的换行符,输入应按保留换行符的方式拆分为行。

  • 库:locale 模块的 format() 函数之前会接受任何字符串,只要不超过一个 %char 指定符。在 Python 2.5 中,参数必须正好是一个 %char 指定符,且周围没有文本。

  • 库:picklecPickle 模块不再接受 __reduce__() 方法返回值为 None;该方法必须返回一个参数元组。模块也不再接受已弃用的 bin 关键字参数。

  • Library: The SimpleXMLRPCServer and DocXMLRPCServer classes now have a rpc_paths attribute that constrains XML-RPC operations to a limited set of URL paths; the default is to allow only '/' and '/RPC2'. Setting rpc_paths to None or an empty tuple disables this path checking.

  • C API:许多函数现在使用 Py_ssize_t 而不是 int,以允许在 64 位机器上处理更多数据。扩展代码可能需要做出相同的更改,以避免警告并支持 64 位机器。有关此更改的讨论,请参阅前面的章节 PEP 353: 使用ssize_t作为索引类型

  • C API:obmalloc 的更改意味着你必须小心,不要混合使用 PyMem_*PyObject_* 系列函数。使用一个系列的 *_Malloc 分配的内存必须使用相应系列的 *_Free 函数释放。

致谢

作者感谢以下人员对本文各种草稿给予的建议、更正和协助: Georg Brandl、Nick Coghlan、Phillip J. Eby、Lars Gustäbel、Raymond Hettinger、Ralf W. Grosse-Kunstleve、Kent Johnson、Iain Lowe、Martin von Löwis、Fredrik Lundh、Andrew McNamara、Skip Montanaro、Gustavo Niemeyer、Paul Prescod、James Pryor、Mike Rovner、Scott Weikart、Barry Warsaw、Thomas Wouters。