python 2.5的新功能

作者

库克林

本文解释了Python2.5中的新特性。python 2.5的最终版本定于2006年8月发布; PEP 356 描述计划的发布计划。

python 2.5中的变化是语言和库改进的有趣组合。我认为,库的增强对于Python的用户社区更为重要,因为添加了一些非常有用的包。新模块包括用于XML处理的elementtree (xml.etree )sqlite数据库模块 (sqlitectypes 用于调用C函数的模块。

语言变化具有中等意义。添加了一些令人愉快的新功能,但大多数功能并不是您每天都要使用的功能。条件表达式最终使用新的语法添加到语言中;请参见第节 PEP 308:条件表达式 . 'with' 语句将使编写清理代码更加容易(第节 PEP 343:“with”声明 )现在可以将值传递到生成器(节 PEP 342:生成器的新功能 )导入现在可以显示为绝对或相对(节 PEP 328:绝对和相对输入 )一些异常处理的角情况处理得更好(第 PEP 341: Unified try/except/finally )所有这些改进都是值得的,但是它们是对一种或另一种特定语言特性的改进;它们都不是对Python语义的广泛修改。

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

本文并不试图成为新特性的完整规范,而是使用有用的示例简要介绍更改。有关完整的详细信息,您应该始终参考位于https://docs.python.org的python 2.5文档。如果您想了解完整的实现和设计原理,请参阅PEP以了解特定的新特性。

欢迎使用此文档的注释、建议和错误报告;请将它们通过电子邮件发送给作者或在python bug tracker中打开一个bug。

PEP 308:条件表达式

很长一段时间以来,人们一直在请求编写条件表达式的方法,条件表达式是返回值A或值B的表达式,这取决于布尔值是真是假。条件表达式允许您编写一个与以下语句具有相同效果的赋值语句:

if condition:
    x = true_value
else:
    x = false_value

关于python dev和comp.lang.python的语法讨论没完没了。甚至举行了一次投票,发现大多数选民希望以某种形式表达条件,但没有明显多数人类似于的句法。候选人包括C cond ? true_v : false_vif cond then true_v else false_v 以及其他16种变体。

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

x = true_value if condition else false_value

与现有的布尔表达式一样,计算仍然很懒惰,因此计算的顺序会跳一点。这个 条件 首先计算中间的表达式,然后 true_value 仅当条件为真时才计算表达式。同样, false_value 仅当条件为false时才计算表达式。

这种语法可能看起来很奇怪,而且是向后的;为什么条件 中间的 在前面,而不是在C的前面。 c ? x : y ?通过将新语法应用于标准库中的模块并查看结果代码的读取方式,检查了该决定。在使用条件表达式的许多情况下,一个值似乎是“常见情况”,一个值是“特殊情况”,仅在不满足条件的少数情况下使用。条件语法使这种模式更加明显:

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

我把上面的陈述理解为“这里 内容 通常分配的值为 doc+'\n' 有时 doc 是空的,在这种情况下返回一个空字符串。“我怀疑在没有明确的常见和不常见的情况下,我会经常使用条件表达式。

有人讨论过语言是否需要用括号括起来的条件表达式。决定是为了 not 在Python语言的语法中需要括号,但就样式而言,我认为您应该始终使用它们。考虑这两种说法:

# First version -- no parens
level = 1 if logging else 0

# Second version -- with parens
level = (1 if logging else 0)

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

包括括号的另一个原因是:列表理解和lambda的一些奇怪的组合可能看起来像不正确的条件表达式。见 PEP 308 例如。如果在条件表达式周围加上括号,就不会遇到这种情况。

参见

PEP 308 -条件表达式

由Guido van Rossum和Raymond D.Hettinger编写的PEP;由Thomas Wouters实施。

PEP 309:部分功能应用

这个 functools 模块旨在包含用于功能性编程的工具。

本模块中的一个有用工具是 partial() 功能。对于以函数样式编写的程序,有时您需要构造现有函数的变体,这些函数中填充了一些参数。考虑使用python函数 f(a, b, c) ;您可以创建一个新函数 g(b, c) 相当于 f(1, b, c) . 这被称为“部分函数应用”。

partial() 接受参数 (function, arg1, arg2, ... kwarg1=value1, kwarg2=value2) .结果对象是可调用的,因此您可以调用它来调用 function 用填充的参数。

下面是一个小但现实的例子:

import functools

def log (message, subsystem):
    "Write the contents of 'message' to the specified subsystem."
    print '%s: %s' % (subsystem, message)
    ...

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

下面是另一个例子,来自一个使用pygtk的程序。这里动态构建了一个上下文相关的弹出菜单。为菜单选项提供的回调是 open_item() 方法,其中提供了第一个参数。::

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

中的另一个函数 functools 模块是 update_wrapper(wrapper, wrapped) 帮助您编写行为良好的装饰器的函数。 update_wrapper() 将name、module和docstring属性复制到封装函数,以便更容易理解封装函数内的回溯。例如,您可以写:

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

wraps() 是一个装饰器,可以在自己的装饰器中使用它来复制封装函数的信息。前一个示例的另一个版本是:

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

向distutils添加了一些简单的依赖性支持。这个 setup() 函数现在具有 requiresprovidesobsoletes 关键字参数。当您使用 sdist 命令,依赖项信息将记录在 PKG-INFO 文件。

另一个新的关键字参数是 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),
     )

在https://pypi.org上对python包索引的另一个新增强是存储包的源文件和二进制文件。新的 upload distutils命令将把包上载到存储库。

在上载包之前,必须能够使用 sdist distutils命令。一旦成功,你就可以运行了 python setup.py upload 将您的包添加到pypi存档。或者,您可以通过提供 --sign--identity 选项。

包上传由Martin von L_wis和Richard Jones实施。

参见

PEP 314 -python软件包1.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

这定义了一个名为 pkg 包含 pkg.mainpkg.string 子模块。

考虑中的代码 main.py 模块。如果它执行语句会发生什么 import string ?在python 2.4及更早版本中,它将首先在包的目录中查找以执行相对导入,查找 pkg/string.py ,将该文件的内容作为 pkg.string 模块,并且该模块绑定到名称 stringpkg.main 模块的命名空间。

这很好,如果 pkg.string 是你想要的。但是如果你想要 Python 的标准呢 string 模块?没有什么可以忽略的 pkg.string 寻找标准模块;一般来说,您必须查看 sys.modules 有点不干净。霍尔格·克里克的 py.std 包提供了从标准库执行导入的更整洁的方式, import py; py.std.string.join() 但该包并不能在所有的python安装中使用。

阅读依赖于相对导入的代码也不太清楚,因为读者可能会对哪个模块感到困惑, stringpkg.string ,用于。python用户很快就学会了不要在包的子模块名称中复制标准库模块的名称,但是您不能防止在将来的python版本中将子模块的名称用于添加新模块。

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

当使用 from ... import 表格:

# Import names from pkg.string
from .string import name1, name2
# Import pkg.string
from . import string

这将导入 string 与当前包相关的模块,因此 pkg.main 这将导入 NAME1NAME2pkg.string . 其他提前期从当前包的父级开始执行相对导入。例如,在 A.B.C 模块可以做到:

from . import D                 # Imports A.B.D
from .. import E                # Imports A.E
from ..F import G               # Imports A.F.G

前导期间不能与 import modname 输入声明的格式,只有 from ... import 形式。

参见

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

由AAHZ编写的PEP;由Thomas Wouters实施。

https://pylib.readthedocs.io/

Holger Krekel的Py类库,其中包含 py.std 包裹。

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

这个 -m 在python 2.4中添加了一个开关来执行一个模块,因为脚本获得了更多的能力。该开关现在使用一个新模块中的实现,而不是在Python解释器中用C代码实现, runpy .

这个 runpy 模块实现了更复杂的导入机制,因此现在可以在包中运行模块,例如 pychecker.checker . 该模块还支持其他导入机制,如 zipimport 模块。这意味着您可以将.zip存档的路径添加到 sys.path 然后使用 -m 切换到从存档执行代码。

参见

PEP 338 -以脚本形式执行模块

PEP由Nick Coghlan编写并实施。

PEP 341: Unified try/except/finally

在python 2.5之前, try 声明有两种味道。你可以使用 finally 块以确保代码始终被执行,或一个或多个 except 用于捕获特定异常的块。你不能两者结合 except 块和A finally 块,因为为组合版本生成正确的字节码很复杂,而且不清楚组合语句的语义应该是什么。

Guido van Rossum花了一些时间来研究Java,它支持等价的组合。 except 块和A finally 块,这澄清了语句的含义。在Python2.5中,现在可以编写:

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

代码在 block-1 执行。如果代码引发异常,则 except 测试块:如果异常属于类 Exception1handler-1 执行;否则,如果它属于类 Exception2handler-2 执行等等。如果未引发异常,则 else-block 执行。

不管之前发生了什么, final-block 在代码块完成并处理任何引发的异常后执行。即使异常处理程序或 else-block 并引发一个新的异常,其中的代码 final-block 仍在运行。

参见

PEP 341 -统一尝试,除了最后尝试

由Georg Brandl编写的PEP;由Thomas Lee实施。

PEP 342:生成器的新功能

python 2.5添加了一种简单的传递值的方法 into 生成器。正如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 value provided, change counter
        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 通常会回来 None ,所以您应该经常检查这个案例。不要只在表达式中使用它的值,除非您确定 send() 方法将是恢复生成器功能的唯一方法。

除了 send() ,生成器上还有两种新方法:

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

  • close() 提出新的 GeneratorExit 生成器内终止迭代的异常。收到此异常时,生成器的代码必须 GeneratorExitStopIteration . 抓住 GeneratorExit 异常并返回值是非法的,将触发 RuntimeError ;如果函数引发其他异常,则该异常将传播到调用方。 close() 当生成器被垃圾收集时,也将由Python的垃圾收集器调用。

    如果需要在 GeneratorExit 发生,我建议使用 try: ... finally: 套间而不是套间 GeneratorExit .

这些变化的累积效应是将生成器从单向信息生产者转变为生产者和消费者。

生成器也变成 协同程序 子程序的一种更通用的形式。子例程在一个点输入,在另一个点(函数的顶部,以及 return 语句),但是协程可以在许多不同的点(即 yield 陈述)。我们必须找出在Python中有效地使用协程的模式。

添加 close() 方法有一个不明显的副作用。 close() 当生成器被垃圾收集时调用,这意味着生成器的代码在生成器被销毁之前有最后一次运行的机会。最后一次机会意味着 try...finally 现在可以保证生成器中的语句正常工作; finally 子句现在总是有机会运行。你不能混合的句法限制 yield 带有 try...finally 因此套房已被拆除。这似乎是一个小的语言琐事,但使用生成器和 try...finally 为了实现 with 声明描述人 PEP 343 . 我将在下面的部分中查看这个新声明。

这一变化的另一个更为深奥的影响是:以前, gi_frame 生成器的属性始终是帧对象。现在有可能 gi_frame 成为 None 一旦生成器耗尽。

参见

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

由Guido van Rossum和Phillip J.Eby编写的PEP;由Phillip J.Eby实施。包括生成器作为协程的一些更高级的应用示例。

这些功能的早期版本在 PEP 288 作者:Raymond Hettinger和 PEP 325 萨缪尔·佩德罗尼。

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

关于协程的维基百科条目。

网址:http://www.sidhe.org/~dan/blog/archives/000178.html

丹·苏加斯基从Perl的角度对协程进行了解释。

PEP 343:“with”声明

'with' 语句澄清了以前将使用的代码 try...finally 块以确保执行清理代码。在本节中,我将讨论通常使用的语句。在下一节中,我将检查实现细节,并演示如何编写用于此语句的对象。

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

with expression [as variable]:
    with-block

对表达式进行了计算,它应生成支持上下文管理协议的对象(即, __enter__()__exit__() 方法。

对象的 __enter__() 以前调用过 with-block 执行,因此可以运行设置代码。它还可以返回绑定到名称的值 变量 ,如果给出的话。(请注意 变量not 分配结果 表达

执行后 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
        ... more processing code ...

执行此语句后,中的文件对象 f 将自动关闭,即使 for 循环在块中部分引发了异常。

注解

在这种情况下, f 是由创建的同一对象 open() ,因为 file.__enter__() 返回 self .

这个 threading 模块的锁和条件变量还支持 'with' 语句::

lock = threading.Lock()
with lock:
    # Critical section of code
    ...

在执行块之前获取锁,并且在块完成后总是释放锁。

新的 localcontext() 功能在 decimal 模块使保存和恢复当前十进制上下文变得容易,后者封装了计算所需的精度和舍入特征:

from decimal import Decimal, Context, localcontext

# Displays with default precision of 28 digits
v = Decimal('578')
print v.sqrt()

with localcontext(Context(prec=16)):
    # All code in this block uses a precision of 16 digits.
    # The original context is restored on exiting the block.
    print v.sqrt()

编写上下文管理器

在引擎盖下, 'with' 声明相当复杂。大多数人只会使用' with '在具有现有对象的公司中,不需要知道这些详细信息,因此如果愿意,可以跳过此部分的其余部分。新对象的作者需要了解底层实现的细节,并且应该继续阅读。

对上下文管理协议的高级解释是:

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

  • 上下文管理器的 __enter__() 方法被调用。返回的值分配给 VAR . 如果没有 'as VAR' 子句存在,该值只是被丢弃。

  • 代码在 BLOCK 执行。

  • 如果 BLOCK 引发异常, __exit__(type, value, traceback) 用异常详细信息调用,返回的值与 sys.exc_info() . 方法的返回值控制是否重新引发异常:任何错误值都会重新引发异常,并且 True 将导致抑制它。您将很少希望抑制异常,因为如果执行此操作,则包含 'with' 语句的代码的作者将永远不会意识到发生了任何错误。

  • 如果 BLOCK 没有提出例外, __exit__() 方法仍被调用,但 typevalue追溯 都是 None .

让我们考虑一个例子。我不会提供详细的代码,但只会勾画出支持事务的数据库所需的方法。

(对于不熟悉数据库术语的人:对数据库的一组更改被分组到一个事务中。事务可以是提交的,也就是说所有的更改都被写入数据库,或者回滚,这意味着所有的更改都被丢弃,并且数据库是不变的。有关更多信息,请参阅任何数据库教科书。)

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

db_connection = DatabaseConnection()
with db_connection as cursor:
    cursor.execute('insert into ...')
    cursor.execute('delete from ...')
    # ... more operations ...

如果块中的代码运行无误,则应提交事务;如果出现异常,则应回滚事务。以下是的基本接口 DatabaseConnection 我假设:

class DatabaseConnection:
    # Database interface
    def cursor (self):
        "Returns a cursor object and starts a new transaction"
    def commit (self):
        "Commits current transaction"
    def rollback (self):
        "Rolls back current transaction"

这个 __enter__() 方法非常简单,只需启动一个新事务。对于这个应用程序,产生的光标对象将是一个有用的结果,因此该方法将返回它。然后用户可以添加 as cursor 到其 'with' 语句将光标绑定到变量名。::

class DatabaseConnection:
    ...
    def __enter__ (self):
        # Code to start a new transaction
        cursor = self.cursor()
        return cursor

这个 __exit__() 方法是最复杂的,因为它是大部分工作都必须完成的地方。方法必须检查是否发生异常。如果没有异常,则提交事务。如果发生异常,事务将回滚。

在下面的代码中,执行将从函数的末尾脱落,返回 None . None 为false,因此将自动重新引发异常。如果您愿意,可以更明确地添加 return 位于标记位置的语句。::

class DatabaseConnection:
    ...
    def __exit__ (self, type, value, tb):
        if tb is None:
            # No exception, so commit
            self.commit()
        else:
            # Exception occurred, so rollback.
            self.rollback()
            # return False

ContextLib模块

新的 contextlib 模块提供一些函数和修饰符,这些函数和修饰符对于编写用于 'with' 语句的对象很有用。

装饰器被称为 contextmanager() ,并允许编写单个生成器函数,而不是定义新类。生成器应只生成一个值。代码到 yield 将作为 __enter__() 方法,生成的值将是方法的返回值,该值将绑定到 'with' 语句中的变量 as 条款(如有)。后面的代码 yield 将在 __exit__() 方法。在块中引发的任何异常都将由 yield 语句。

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

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显示为a'生成的代码 '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:
    # Log error...
    # Continue running program...

在Python2.5中,现在可以编写 except Exception 为了获得相同的结果,捕获通常指示错误但离开的所有异常 KeyboardInterruptSystemExit 独自一人。在以前的版本中, except: 仍然捕获所有异常。

Python3.0的目标是要求作为异常引发的任何类从 BaseException 或是某个 BaseException 以及python 2.x系列中的未来版本可能会开始强制执行此约束。因此,我建议您开始让所有的异常类从 Exception 现在。有人建议 except: 表单应该在python 3.0中删除,但guido van rossum还没有决定是否要这样做。

将字符串作为异常引发,如在语句中 raise "Error occurred" 在python 2.5中已弃用,将触发警告。其目的是能够在几个版本中删除字符串异常特性。

参见

PEP 352 -异常所需的超类

由布雷特加农和吉多范罗森撰写的PEP计划;由布雷特加农实施。

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

使用新的 Py_ssize_t 类型定义而不是 int 将允许解释器在64位平台上处理更多数据。此更改不会影响32位平台上的Python容量。

各种各样的python解释器使用C int 键入以存储大小或计数;例如,列表或元组中的项数存储在 int . 大多数64位平台的C编译器仍然定义 int 作为一个32位类型,这意味着列表只能容纳 2**31 - 1 =2147483647项。(实际上,64位C编译器可以使用一些不同的编程模型——请参见http://www.unix.org/version2/whatsnew/lp64_wp.html进行讨论——但最常见的模型是 int 作为32位。

在32位平台上,2147483647项的限制并不重要,因为在达到长度限制之前,内存将耗尽。每个列表项都需要一个指针空间(4个字节),再加上一个 PyObject 表示项。二十一亿四千七百四十八万三千六百四十七 * 4已经超过了32位地址空间所能包含的字节数。

然而,在64位平台上处理这么多内存是可能的。这个大小的列表的指针只需要16 gib的空间,所以Python程序员可以构造这么大的列表也不是不合理的。因此,必须更改python解释器以使用除 int ,这将是64位平台上的64位类型。这一变化将导致64位计算机上的不兼容,因此现在进行转换被认为是值得的,而64位用户的数量仍然相对较少。(在5或10年内,我们可以 all 在64位机器上,那么转换会更痛苦。)

此更改对C扩展模块的作者影响最大。python字符串和容器类型(如列表和元组)现在使用 Py_ssize_t 储存它们的尺寸。功能,例如 PyList_Size() 现在回来 Py_ssize_t . 因此,扩展模块中的代码可能需要将一些变量更改为 Py_ssize_t .

这个 PyArg_ParseTuple()Py_BuildValue() 函数有一个新的转换代码, n ,为了 Py_ssize_t . PyArg_ParseTuple()s#t# 静止输出 int 默认情况下,但可以定义宏 PY_SSIZE_T_CLEAN 包括之前 Python.h 让他们回来 Py_ssize_t .

PEP 353 有一个关于转换准则的部分,扩展作者应该阅读该部分以了解支持64位平台。

参见

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

PEP由Martin von L_wis编写并实施。

PEP 357:指数法

numpy开发人员遇到了一个问题,只能通过添加新的特殊方法来解决。 __index__() . 使用切片表示法时,如 [start:stop:step] ,的值 开始stopstep 索引必须都是整数或长整数。numpy定义了与8、16、32和64位的无符号整数和有符号整数相对应的各种专用整数类型,但无法表示这些类型可以用作切片索引。

切片不能只使用现有的 __int__() 方法,因为该方法还用于实现对整数的强制。如果使用切片 __int__() ,浮点数也将成为合法的切片索引,这显然是一种不可取的行为。

相反,一个新的特殊方法 __index__() 加入。它不接受任何参数,并返回一个整数,给出要使用的切片索引。例如::

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

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

相应的 nb_index 插槽被添加到C级 PyNumberMethods 允许C扩展实现此协议的结构。 PyNumber_Index(obj) 可在扩展代码中用于调用 __index__() 函数并检索其结果。

参见

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

由特拉维斯·奥列芬特编写和实现。

其他语言更改

下面是python 2.5对核心python语言所做的所有更改。

  • 这个 dict 类型有一个新的钩子,它允许子类在字典中未包含键时提供默认值。当找不到键时,字典的 __missing__(key) 将调用方法。这个钩子是用来实现新的 defaultdict 类中 collections 模块。以下示例定义了一个字典,该字典为任何缺少的键返回零:

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

    这个 find(S) 方法通常用于获取索引,然后使用该索引对字符串进行切片,并获取分隔符前后的片段。 partition(sep) 将此模式浓缩为一个方法调用,该方法调用返回一个3元组,其中包含分隔符之前的子字符串、分隔符本身以及分隔符之后的子字符串。如果找不到分隔符,则元组的第一个元素是整个字符串,其他两个元素为空。 rpartition(sep) 还返回3元组,但从字符串结尾开始搜索;the r 表示“反向”。

    一些例子:

    >>> ('http://www.python.org').partition('://')
    ('http', '://', 'www.python.org')
    >>> ('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.python.org'.rpartition('.')
    ('www.python', '.', 'org')
    >>> 'www.python.org'.rpartition(':')
    ('', '', 'www.python.org')
    

    (由Fredrik Lundh根据Raymond Hettinger的建议实施。)

  • 这个 startswith()endswith() 字符串类型的方法现在接受要检查的字符串元组。::

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

    ( 由Georg Brandl根据Tom Lynn的建议实施。)

  • 这个 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() 将从该函数返回具有最小/最大返回值的元素。例如,要查找列表中最长的字符串,可以执行以下操作:

    L = ['medium', 'longest', 'short']
    # Prints 'longest'
    print max(L, key=len)
    # Prints 'short', because lexicographically 'short' has the largest value
    print max(L)
    

    ( 史蒂文·贝萨德和雷蒙德·赫廷格供稿。)

  • 两个新的内置功能, any()all() ,计算迭代器是否包含任何真值或假值。 any() 返回 True 如果迭代器返回的任何值为真,则返回 False . all() 返回 True 只有当迭代器返回的所有值都计算为真时。(由Guido van Rossum建议,由Raymond Hettinger实施。)

  • 类的结果 __hash__() 方法现在可以是长整数或常规整数。如果返回长整数,则取该值的hash值。在早期版本中,hash值要求为常规整数,但在2.5中, id() 内置被更改为始终返回非负数,用户似乎经常使用 id(self) 在里面 __hash__() 方法(尽管不鼓励这样做)。

  • ASCII现在是模块的默认编码。如果一个模块包含带有8位字符的字符串文本,但没有编码声明,那么它现在就是一个语法错误。在Python2.4中,这引发了一个警告,而不是语法错误。参见 PEP 263 有关如何声明模块的编码;例如,可以在源文件的顶部附近添加这样的行:

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

    >>> chr(128) == unichr(128)   # Can't convert chr(128) to Unicode
    __main__:1: UnicodeWarning: Unicode equal comparison failed
      to convert both arguments to Unicode - interpreting them
      as being unequal
    False
    >>> chr(127) == unichr(127)   # chr(127) can be converted
    True
    

    以前,这会提高 UnicodeDecodeError 例外,但在2.5中,这可能会导致在访问字典时出现令人费解的问题。如果你抬头看 unichr(128)chr(128) 被用作钥匙,你会得到 UnicodeDecodeError 例外。2.5中的其他更改导致此异常被引发,而不是被中的代码抑制。 dictobject.c 它实现了字典。

    为这种比较引发异常是完全正确的,但是更改可能破坏了代码,因此 UnicodeWarning 介绍。

    ( 由Marc Andr_Lemburg实施)

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

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

    class C():
        pass
    

    ( 由布雷特加农炮实施。)

交互式解释程序更改

在交互式解释器中, quitexit 一直以来都是字符串,因此新用户在尝试退出时会收到一些有帮助的消息:

>>> quit
'Use Ctrl-D (i.e. EOF) to exit.'

在python 2.5中, quitexit 现在的对象仍然可以生成自己的字符串表示,但也可以调用。尝试的新手 quit()exit() 现在将按预期退出解释器。(由Georg Brandl实施。)

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

优化

在2006年5月21日至28日在冰岛雷克雅未克举行的“速度冲刺”(needforspeed sprint)活动中,开发了几个优化方案。Sprint专注于提高CPython实施的速度,由EWT LLC提供资金,并得到了CCP游戏的本地支持。在这个sprint中添加的那些优化特别标记在下面的列表中。

  • 当它们在python 2.4中被引入时,内置的 setfrozenset 类型是在Python字典类型的基础上构建的。在2.5中,内部数据结构是为实现集合而定制的,因此集合将使用更少的内存,并且速度更快。(由Raymond Hettinger实施。)

  • 一些Unicode操作(如查找子字符串、字符串拆分以及字符映射编码和解码)的速度已经得到了提高。(子字符串搜索和拆分改进由Fredrik Lundh和Andrew Dalke在Needforspeed Sprint中添加。Walter D_rwald和Martin von L_wis改进了字符映射。

  • 这个 long(str, base) 由于计算的中间结果更少,函数在长数字字符串上的速度更快。峰值适用于800-1000位左右的字符串,其中函数速度快6倍。(由艾伦·麦金泰尔(Alan McIntyre)提供,并致力于速度冲刺的需要。)

  • 将迭代文件与 for line in file 并调用文件对象的 read()/readline()/readlines() 方法。迭代使用内部缓冲区和 read*() 方法不使用该缓冲区。相反,它们会返回缓冲区后面的数据,导致数据出现无序。混合迭代和这些方法现在将触发 ValueErrorread*() 方法。(由Thomas Wouters实施。)

  • 这个 struct 模块现在将结构格式字符串编译为内部表示并缓存该表示,从而使速度提高20%。(Bob Ipolito在Needforspeed Sprint的贡献。)

  • 这个 re 通过切换到python的分配器函数而不是系统的,模块的速度提高了1%或2%。 malloc()free() . (由杰克·迪德里奇在必要的速度冲刺中贡献。)

  • 代码生成器的窥视孔优化器现在在表达式中执行简单的常量折叠。如果你写的东西 a = 2+3 ,代码生成器将执行算术并生成与 a = 5 . (由Raymond Hettinger提出并实施。)

  • 函数调用现在更快了,因为代码对象现在在代码对象的内部字段中保留最近完成的帧(“僵尸帧”),下次调用代码对象时重用它。(由Michael Hudson提供的原始补丁,由Armin Rigo和Richard Jones修改;致力于速度冲刺。)帧对象也稍微小一些,这可以改善缓存位置并减少内存使用。(尼尔·诺维茨供稿)

  • Python的内置异常现在是新的风格类,这一变化大大加快了实例化速度。因此,Python2.5中的异常处理比2.4中的异常处理快30%。(由理查德·琼斯、乔治·布兰德和肖恩·雷夫施耐德在Needforspeed Sprint上撰稿。)

  • 现在导入缓存所尝试的路径,记录它们是否存在,以便解释器减少 open()stat() 启动时调用。(马丁·冯·维斯和乔治·布兰德提供。)

新的、改进的和删除的模块

标准库在python 2.5中收到了许多增强和错误修复。下面是最显著变化的部分列表,按模块名称的字母顺序排列。查阅 Misc/NEWS 在源代码树中查找更完整的更改列表,或者查看SVN日志以获取所有详细信息。

  • 这个 audioop 模块现在支持A-律编码,U-律编码的编码得到了改进。(由Lars Immisch提供)

  • 这个 codecs 模块获得了对增量编解码器的支持。这个 codec.lookup() 函数现在返回 CodecInfo 实例而不是元组。 CodecInfo 实例的行为类似于4元组以保持向后兼容性,但也具有属性 encodedecodeincrementalencoderincrementaldecoderstreamwriterstreamreader . 增量编解码器可以接收多个块中的输入并生成输出;输出与整个输入被馈送到非增量编解码器时的输出相同。见 codecs 有关详细信息的模块文档。(由Walter D_rwald设计和实施。)

  • 这个 collections 模块获得了一种新的类型, defaultdict ,这是标准的子类 dict 类型。新类型的行为主要类似于字典,但在不存在键时构造默认值,自动将其添加到字典中以获取请求的键值。

    第一个参数 defaultdict 的构造函数是一个factory函数,每当请求键但未找到时都会调用该函数。此factory函数不接收任何参数,因此可以使用内置类型构造函数,例如 list()int() . 例如,您可以根据单词的首字母创建单词索引,如下所示:

    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提供。)

  • 这个 deque 由提供的双端队列类型 collections 模块现在有一个 remove(value) 删除第一次出现的 value 在队列中,引发 ValueError 如果找不到该值。(Raymond Hettinger提供。)

  • 新模块: contextlib 模块包含用于新的 'with' 语句的帮助程序函数。见节 ContextLib模块 有关此模块的更多信息。

  • 新模块: cProfile 模块是现有的C实现 profile 开销更低的模块。模块的接口与 profile :你运行 cProfile.run('main()') 要分析一个函数,可以将配置文件数据保存到一个文件等。还不知道hotshot profiler是否与 profile 模块的接口将在将来的Python版本中继续维护。(由Armin Rigo提供。)

    此外, pstats 分析分析器测量的数据的模块现在支持通过提供 流动 参数 Stats 构造函数。(由Skip Montanaro提供。)

  • 这个 csv 模块以逗号分隔的值格式解析文件,收到了一些增强功能和一些错误修复。现在可以通过调用 csv.field_size_limit(new_limit) 函数;省略 new_limit 参数将返回当前设置的限制。这个 reader 类现在有一个 line_num 统计从源读取的物理行数的属性;记录可以跨多个物理行,因此 line_num 与读取的记录数不同。

    csv解析器现在对多行引用字段更严格。以前,如果一行在带引号的字段中结束,但没有结束换行符,则换行符将插入返回的字段中。此行为在读取包含回车符的文件时会导致问题,因此代码被更改为返回字段而不插入换行符。因此,如果字段中嵌入的换行很重要,则应以保留换行符的方式将输入拆分为行。

    ( 由Skip Montanaro和Andrew McNamara提供。)

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

    from datetime import datetime
    
    ts = datetime.strptime('10:13:15 2006-03-07',
                           '%H:%M:%S %Y-%m-%d')
    
  • 这个 SequenceMatcher.get_matching_blocks() 方法在 difflib 模块现在保证返回描述匹配子序列的块的最小列表。以前,该算法偶尔会将匹配元素的块分解为两个列表项。(蒂姆·彼得斯的增强。)

  • 这个 doctest 模块获得 SKIP 一个选项,它可以防止示例被执行。这适用于代码片段,这些代码片段是面向读者的使用示例,而不是实际的测试用例。

    encoding 参数已添加到 testfile() 函数和 DocFileSuite 类以指定文件的编码。这使得在包含在docstring中的测试中更容易使用非ASCII字符。(由比约恩·蒂勒纽斯提供。)

  • 这个 email 包已更新为4.0版。(巴里·华沙供稿)

  • 这个 fileinput 模块变得更灵活。现在支持Unicode文件名,并且 mode 默认为的参数 "r" 已添加到 input() 函数允许以二进制或 universal newlines 模式。另一个新参数, 开口钩 ,允许您使用除 open() 打开输入文件。当您在一组文件上迭代时, FileInput 对象的新 fileno() 返回当前打开文件的文件描述符。(由乔治布兰德提供。)

  • gc 模块,新的 get_count() 函数返回一个三元组,其中包含三个GC代的当前集合计数。这是垃圾收集器的记帐信息;当这些计数达到指定阈值时,将进行垃圾收集清除。现有的 gc.collect() 函数现在接受一个可选的 一代 参数0、1或2指定要收集的生成。(巴里·华沙供稿)

  • 这个 nsmallest() and nlargest() functions in the heapq module now support a key keyword parameter similar to the one provided by the min()/max() 功能和 sort() 方法。例如::

    >>> import heapq
    >>> L = ["short", 'medium', 'longest', 'longer still']
    >>> heapq.nsmallest(2, L)  # Return two lowest elements, lexicographically
    ['longer still', 'longest']
    >>> heapq.nsmallest(2, L, key=len)   # Return two shortest elements
    ['short', 'medium']
    

    ( Raymond Hettinger提供。)

  • 这个 itertools.islice() 函数现在接受 None 对于start和step参数。这使得它更兼容slice对象的属性,因此现在可以编写以下内容:

    s = slice(5)     # Create slice object
    itertools.islice(iterable, s.start, s.stop, s.step)
    

    ( Raymond Hettinger提供。)

  • 这个 format() 功能在 locale 修改了模块,增加了两个新功能。 format_string()currency() .

    这个 format() 函数的 val 参数以前可以是一个字符串,只要不出现多个%char说明符;现在参数必须正好是一个%char说明符,并且没有周围的文本。可选的 monetary 还添加了参数,如果 True ,将在三位数组之间放置分隔符时使用区域设置的货币格式规则。

    要使用多个%char说明符格式化字符串,请使用新的 format_string() 像这样工作的功能 format() 但也支持将%char说明符与任意文本混合。

    一个新的 currency() 还添加了根据当前区域设置格式化数字的函数。

    ( 由乔治布兰德提供。)

  • 这个 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() 锁定/解锁邮箱。以下示例将maildir格式邮箱转换为mbox格式邮箱:

    import mailbox
    
    # 'factory=None' uses email.Message.Message as the class representing
    # individual messages.
    src = mailbox.Maildir('maildir', factory=None)
    dest = mailbox.mbox('/tmp/mbox')
    
    for msg in src:
        dest.add(msg)
    

    (由Gregory K.Johnson提供。资金由谷歌2005年夏天的代码提供。)

  • 新模块: msilib 模块允许创建Microsoft安装程序 .msi 文件和cab文件。一些支持阅读 .msi 数据库也包括在内。(马丁·冯·L·威斯供稿)

  • 这个 nis 模块现在支持通过提供 参数 nis.match()nis.maps() 功能。(本·贝尔供稿)

  • 这个 operator 模块的 itemgetter()attrgetter() 函数现在支持多个字段。像这样的调用 operator.attrgetter('a', 'b') 将返回一个检索 ab 属性。将此新功能与 sort() 方法的 key 参数允许您使用多个字段轻松排序列表。(Raymond Hettinger提供。)

  • 这个 optparse 模块更新为optik库的1.5.1版本。这个 OptionParser 类获 epilog 属性,将在帮助消息之后打印的字符串,以及 destroy() 方法中断由对象创建的引用循环。(格雷格·沃德供稿)

  • 这个 os 模块发生了一些变化。这个 stat_float_times 变量现在默认为真,这意味着 os.stat() 现在将以浮动形式返回时间值。(这并不一定意味着 os.stat() 将返回精确到几分之一秒的时间;并非所有系统都支持这种精度。)

    常量命名 os.SEEK_SETos.SEEK_CURos.SEEK_END 已添加;这些是 os.lseek() 功能。用于锁定的两个新常量是 os.O_SHLOCKos.O_EXLOCK .

    两个新功能, wait3()wait4() ,补充说。它们是相似的 waitpid() 函数,它等待子进程退出并返回进程ID及其退出状态的元组,但 wait3()wait4() 返回附加信息。 wait3() 不接受进程ID作为输入,因此它等待任何子进程退出并返回 process-idexit-statusresource-usageresource.getrusage() 功能。 wait4(pid) 是否采用进程ID(由Chad J.Schroeder提供)。

    在FreeBSD上, os.stat() 函数现在返回纳秒分辨率的时间,返回的对象现在 st_genst_birthtime . 这个 st_flags 如果平台支持,属性也可用。(由Antti Louko和Diego Petten_提供。)

  • 由提供的python调试器 pdb 模块现在可以存储到达断点并停止执行时要执行的命令列表。创建断点1后,输入 commands 1 并输入一系列要执行的命令,用 end . 命令列表可以包括恢复执行的命令,例如 continuenext . (由Gr_Goire Dooms贡献)

  • 这个 picklecPickle 模块不再接受返回值 None__reduce__() 方法;该方法必须返回参数的元组。返回的能力 None 在python 2.4中已弃用,因此这就完成了功能的删除。

  • 这个 pkgutil 该模块包含用于查找包的各种实用程序功能,经过增强以支持 PEP 302 的导入挂钩,现在也可以用于存储在zip格式存档文件中的包。(Phillip J.Eby撰稿)

  • Marc Andr_Lemburg的PyBench基准套房现已包含在 Tools/pybench 目录。pybench套件是对常用的 pystone.py 因为pybench提供了一个更详细的解释程序速度测量。它多次执行特定的操作,如函数调用、元组切片、方法查找和数值操作,而不是执行许多不同的操作,并将结果减少到单个数字,如 pystone.py 做。

  • 这个 pyexpat 模块现在使用了expat解析器的2.0版。(特伦特·米克供稿)

  • 这个 Queue 由提供的类 Queue 模块获得了两种新方法。 join() 阻止,直到检索到队列中的所有项并完成对这些项的所有处理工作。工作线程调用另一个新方法, task_done() ,表示已完成对项的处理。(Raymond Hettinger提供。)

  • 老年人 regexregsub 自python 2.0以来一直被弃用的模块最终被删除。其他删除的模块: statcachetzparsewhrandom .

  • 同时删除: lib-old 目录,其中包括古代模块,如 dircmpni 被移除了。 lib-old 没有违约 sys.path ,因此,除非您的程序显式地将目录添加到 sys.path ,此删除不应影响代码。

  • 这个 rlcompleter 模块不再依赖于导入 readline 模块,因此现在可以在非UNIX平台上工作。(罗伯特·基恩德的补丁)

  • 这个 SimpleXMLRPCServerDocXMLRPCServer 课程现在有一个 rpc_paths 将XML-RPC操作约束到一组有限的URL路径的属性;默认值为仅允许 '/''/RPC2' . 设置 rpc_pathsNone 或者一个空元组禁用此路径检查。

  • 这个 socket 模块现在支持 AF_NETLINK Linux上的套接字,多亏了Philippe Biondi的一个补丁。netlink sockets是一种特定于Linux的机制,用于用户空间进程和内核代码之间的通信;有关它们的介绍性文章位于https://www.linuxjournal.com/article/7356。在python代码中,netlink地址表示为2个整数的元组, (pid, group_mask) .

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

    还获得了套接字对象 getfamily()gettype()getproto() 用于检索套接字的族、类型和协议值的访问器方法。

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

  • 这个 struct 因为它将格式字符串编译为 Struct 对象与 pack()unpack() 方法。这与 re 模块允许您创建已编译的正则表达式对象。您仍然可以使用模块级 pack()unpack() 函数;它们将创建 Struct 对象并缓存它们。或者你可以使用 Struct 直接实例:

    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 对象由BobIpolito在NeedForspeed Sprint中实现。对缓冲区对象的支持是由MartinBlais添加的,也是在NeedForspeed Sprint中添加的。)

  • 在2.5开发过程中,python开发人员从cvs切换到subversion。有关确切生成版本的信息可作为 sys.subversion 变量,三元组 (interpreter-name, branch-name, revision-range) . 例如,在写我的2.5副本时,我正在报告 ('CPython', 'trunk', '45313:45315') .

    此信息也可通过 Py_GetBuildInfo() 返回如下生成信息字符串的函数: "trunk:45355:45356M, Apr 13 2006, 07:42:19" . (巴里·华沙供稿)

  • 另一个新功能, sys._current_frames() ,将所有运行线程的当前堆栈帧作为字典返回,将线程标识符映射到调用函数时该线程中当前活动的最顶层堆栈帧。(蒂姆·彼得斯供稿)

  • 这个 TarFile 类中 tarfile 模块现在有一个 extractall() 方法,将存档中的所有成员提取到当前工作目录中。也可以设置一个不同的目录作为提取目标,并且只解包存档成员的一个子集。

    用于以流模式打开的tarfile的压缩现在可以使用该模式自动检测。 'r|*' . (拉尔斯·古斯特·贝尔供稿)

  • 这个 threading 模块现在允许您设置创建新线程时使用的堆栈大小。这个 stack_size([*size*]) 函数返回当前配置的堆栈大小,并提供可选的 size 参数设置新值。并非所有平台都支持更改堆栈大小,但Windows、POSIX线程和OS/2都支持。(安德鲁·麦金泰尔供稿)

  • 这个 unicodedata 模块已更新为使用Unicode字符数据库的4.1.0版。有些规范要求使用3.2.0版,因此仍然可以使用 unicodedata.ucd_3_2_0 .

  • 新模块: uuid 模块根据 RFC 4122 . RFC定义了几个不同的UUID版本,这些版本是从起始字符串、系统属性或纯粹随机生成的。此模块包含 UUID 名为的类和函数 uuid1()uuid3()uuid4()uuid5() 生成不同版本的UUID。(版本2 UUID未在中指定 RFC 4122 和不受此模块支持。)::

    >>> import uuid
    >>> # make a UUID based on the host ID and current time
    >>> uuid.uuid1()
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
    
    >>> # make a UUID using an MD5 hash of a namespace UUID and a name
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
    
    >>> # make a random UUID
    >>> uuid.uuid4()
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
    
    >>> # make a UUID using a SHA-1 hash of a namespace UUID and a name
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
    

    ( 嘉平业供稿)

  • 这个 weakref 模块的 WeakKeyDictionaryWeakValueDictionary 类型获得了迭代字典中包含的弱引用的新方法。 iterkeyrefs()keyrefs() 方法已添加到 WeakKeyDictionaryitervaluerefs()valuerefs() 被添加到 WeakValueDictionary . (小弗雷德·L·德雷克供稿)

  • 这个 webbrowser 模块收到了一些增强。它现在可以作为脚本使用 python -m webbrowser ,以一个URL作为参数;有许多开关可以控制行为 (-n 对于新的浏览器窗口, -t 新标签)。新的模块级功能, open_new()open_new_tab() ,以支持此。模块的 open() 函数支持一个附加功能,即 自动调整 指示是否在可能时升高打开的窗口的参数。一些附加的浏览器被添加到支持的列表中,比如火狐、Opera、Konquerror和Elinks。(由Oleg Broytmann和Georg Brandl提供。)

  • 这个 xmlrpclib 模块现在支持返回 datetime XML-RPC日期类型的对象。供应 use_datetime=Trueloads() 函数或 Unmarshaller 类以启用此功能。(由Skip Montanaro提供。)

  • 这个 zipfile 模块现在支持该格式的zip64版本,这意味着.zip存档现在可以大于4 gib,并且可以包含大于4 gib的单个文件。(罗纳德·奥索伦供稿)

  • 这个 zlib 模块的 CompressDecompress 对象现在支持 copy() 方法,该方法复制对象的内部状态并返回新的 CompressDecompress 对象。(Chris Atlee供稿)

ctypes包

这个 ctypes 由ThomasHeller编写的包已经添加到标准库中。 ctypes 允许在共享库或DLL中调用任意函数。长时间用户可能会记住 dl 模块,它提供加载共享库和调用其中的函数的功能。这个 ctypes 封装更精美。

若要加载共享库或dll,必须创建 CDLL 类并提供共享库或dll的名称或路径。完成后,可以通过将任意函数作为 CDLL 对象。::

import ctypes

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

提供了各种C类型的类型构造函数: c_int()c_float()c_double()c_char_p() (相当于 char* )等等。与Python的类型不同,C版本都是可变的;您可以将它们分配给 value 属性更改封装值。python整数和字符串将自动转换为相应的C类型,但对于其他类型,必须调用正确的类型构造函数。(我的意思是 must ;出错通常会导致解释程序崩溃并出现分段错误。)

你不应该使用 c_char_p() 使用python字符串时,C函数将修改内存区域,因为python字符串应该是不可变的;违反此规则将导致令人费解的错误。当需要可修改的内存区域时,请使用 create_string_buffer() ::

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

假定C函数返回整数,但可以设置 restype 要更改此内容的函数对象的属性:

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

ctypes 还为Python的C API提供了一个封装器,作为 ctypes.pythonapi 对象。这个对象有 not 在调用函数之前释放全局解释器锁,因为调用解释器代码时必须保持锁。有一个 py_object() 将创建一个 PyObject* 指针。简单用法:

import ctypes

d = {}
ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d),
          ctypes.py_object("abc"),  ctypes.py_object(1))
# d is now {'abc', 1}.

别忘了用 py_object() ;如果忽略了它,则最终会出现分段错误。

ctypes 已经存在一段时间了,但是人们仍然编写和分发手工编码的扩展模块,因为您不能依赖 ctypes 在场。也许开发人员将开始在通过 ctypes 而不是扩展模块,现在 ctypes 包含在核心python中。

参见

http://starship.python.net/crew/theller/ctypes/

ctypes网页,包括教程、参考资料和常见问题解答。

文件 ctypes 模块。

ElementTree包

Fredrik Lundh用于处理XML的elementTree库的一个子集已作为 xml.etree . 可用模块包括 ElementTreeElementPathElementInclude 来自elementtree 1.2.6。这个 cElementTree 加速器模块也包括在内。

本节的其余部分将简要概述如何使用elementtree。有关elementtree的完整文档,请访问http://effbot.org/zone/element-index.htm。

element tree将XML文档表示为元素节点树。文档的文本内容存储为 texttail 属性(这是ElementTree和文档对象模型之间的主要区别之一;在DOM中有许多不同类型的节点,包括 TextNode

最常用的解析函数是 parse() ,它接受字符串(假定包含文件名)或类似文件的对象,并返回 ElementTree 实例:

from xml.etree import ElementTree as ET

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

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

一旦你有了 ElementTree 例如,您可以调用 getroot() 获取根的方法 Element 节点。

还有一个 XML() 接受字符串文本并返回 Element 节点(不是 ElementTree )此函数提供了一种合并XML片段的整洁方法,接近XML文本的便利性:

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'th到n'th子元素的列表。

len(elem)

返回子元素的数目。

list(elem)

返回子元素列表。

elem.append(elem2)

添加 元素2 作为一个子项。

elem.insert(index, elem2)

插入物 元素2 在指定的位置。

del elem[n]

删除第n个子元素。

elem.keys()

返回属性名称列表。

elem.get(name)

返回属性值 name .

elem.set(name, value)

为属性设置新值 name .

elem.attrib

检索包含属性的字典。

del elem.attrib[name]

删除属性 name .

注释和处理指令也表示为 Element 节点。要检查节点是注释还是处理指令,请执行以下操作:

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

要生成XML输出,应调用 ElementTree.write() 方法。类似于 parse() ,它可以采用字符串或类似文件的对象::

# Encoding is US-ASCII
tree.write('output.xml')

# Encoding is UTF-8
f = open('output.xml', 'w')
tree.write(f, encoding='utf-8')

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

本节只是对elementtree接口的部分描述。请阅读包裹的官方文件了解更多细节。

参见

http://effbot.org/zone/element-index.htm

元素树的官方文档。

hashlib包

一个新的 hashlib 格雷戈里·史密斯(Gregory P.Smith)编写的模块已被添加以取代 md5sha 模块。 hashlib 添加对其他安全hash(sha-224、sha-256、sha-384和sha-512)的支持。如果可用,模块使用OpenSSL快速实现平台优化算法。

老年人 md5sha 模块仍然以封装器的形式存在于hashlib周围,以保持向后的兼容性。新模块的接口与旧模块的接口非常接近,但并不相同。最重要的区别是用于创建新hash对象的构造函数函数的命名不同。::

# Old versions
h = md5.md5()
h = md5.new()

# New version
h = hashlib.md5()

# Old versions
h = sha.sha()
h = sha.new()

# New version
h = hashlib.sha1()

# Hash that weren't previously available
h = hashlib.sha224()
h = hashlib.sha256()
h = hashlib.sha384()
h = hashlib.sha512()

# Alternative form
h = hashlib.new('md5')          # Provide algorithm as a string

创建hash对象后,其方法与以前相同: update(string) 将指定的字符串散列到当前摘要状态, digest()hexdigest() 以二进制字符串或十六进制数字字符串的形式返回摘要值,以及 copy() 返回具有相同摘要状态的新hash对象。

参见

文件 hashlib 模块。

sqlite3包

pysqlite模块(http://www.pysqlite.org)是sqlite嵌入式数据库的封装,已添加到标准库中的包名称下。 sqlite3 .

sqlite是一个C库,它提供了一个基于磁盘的轻量级数据库,不需要单独的服务器进程,并且允许使用非标准的SQL查询语言变体访问数据库。一些应用程序可以使用sqlite进行内部数据存储。也可以使用sqlite对应用程序进行原型化,然后将代码移植到更大的数据库,如postgresql或oracle。

pysqlite由gerhard h_ring编写,并提供符合DB-API 2.0规范的SQL接口 PEP 249 .

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

要使用该模块,必须首先创建一个 Connection 表示数据库的对象。数据将存储在 /tmp/example 文件::

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

您还可以提供特殊名称 :memory: 在RAM中创建数据库。

一旦你拥有了 Connection ,您可以创建一个 Cursor 对象并调用其 execute() 执行SQL命令的方法:

c = conn.cursor()

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

# Insert a row of data
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")

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

相反,使用db-api的参数替换。放 ? 作为占位符使用值,然后提供值的元组作为光标的第二个参数 execute() 方法。(其他数据库模块可能使用不同的占位符,例如 %s:1 )例如:

# Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)

# Larger example
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)

要在执行select语句后检索数据,可以将光标视为迭代器,调用光标的 fetchone() 方法来检索单个匹配行或调用 fetchall() 获取匹配行的列表。

此示例使用迭代器形式:

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

参见

http://www.pysqlite.org

pysqlite网页。

https://www.sqlite.org

sqlite网页;文档描述支持的SQL方言的语法和可用数据类型。

文件 sqlite3 模块。

PEP 249 -数据库API规范2.0

马克·安德尔·莱姆伯格写的PEP。

wsgiref包

Web服务器网关接口(wsgi)v1.0定义了Web服务器和python Web应用程序之间的标准接口,如中所述。 PEP 333 . 这个 wsgiref 包是wsgi规范的引用实现。

该包包含一个运行wsgi应用程序的基本HTTP服务器;该服务器对调试很有用,但不用于生产。设置服务器只需要几行代码:

from wsgiref import simple_server

wsgi_app = ...

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

参见

http://www.wsgi.org

用于与wsgi相关资源的中心网站。

PEP 333 -python web服务器网关接口v1.0

菲利普·J·埃比写的PEP。

构建和C API更改

对python构建过程和C API的更改包括:

  • 在一个由MartinvonL_wis监督和完美执行的复杂迁移过程中,python源码树从cvs转换为subversion。程序开发为 PEP 347 .

  • Coverity是一家销售名为Prevent的源代码分析工具的公司,它提供了对Python源代码的检查结果。分析发现大约60个bug被迅速修复。许多错误都是重复计数问题,经常发生在错误处理代码中。有关统计信息,请访问https://scan.coverity.com。

  • C API的最大变化来自 PEP 353 ,它将解释程序修改为使用 Py_ssize_t 类型定义而不是 int . 参见前面的部分 PEP 353:使用ssize_t作为索引类型 关于这一变化的讨论。

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

    python代码可以通过使用 compile() 内置和指定 _ast.PyCF_ONLY_AST 作为 flags 参数::

    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]
    

    还没有为AST代码编写官方文档,但是 PEP 339 讨论设计。要开始学习代码,请阅读中各种ast节点的定义 Parser/Python.asdl . python脚本读取此文件并在 Include/Python-ast.h . 这个 PyParser_ASTFromString()PyParser_ASTFromFile() ,定义在 Include/pythonrun.h ,将python source作为输入,并返回表示内容的ast的根。然后可以通过以下方式将此ast转换为代码对象: PyAST_Compile() . 有关详细信息,请阅读源代码,然后就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冲刺的参与者实施。

  • EvanJones对obmalloc的补丁,在2005年的PyconDC的一次谈话中首次描述,被应用。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的更改,这些族现在做不同的事情,不匹配可能会导致segfault。您应该使用python 2.5仔细测试您的C扩展模块。

  • 内置的集合类型现在有了一个官方的C API。调用 PySet_New()PyFrozenSet_New() 要创建新的集合, PySet_Add()PySet_Discard() 添加和删除元素,以及 PySet_Contains()PySet_Size() 检查集合的状态。(Raymond Hettinger提供。)

  • C代码现在可以通过调用 Py_GetBuildInfo() 返回如下生成信息字符串的函数: "trunk:45355:45356M, Apr 13 2006, 07:42:19" . (巴里·华沙供稿)

  • 两个新宏可用于指示当前文件本地的C函数,以便使用更快的调用约定。 Py_LOCAL(type) 将函数声明为返回指定的 type 并使用快速调用限定符。 Py_LOCAL_INLINE(type) 做同样的事情,也请求函数是内联的。如果 PY_LOCAL_AGGRESSIVE() 在前面定义 python.h 其中包括,为模块启用了一组更具攻击性的优化;您应该对结果进行基准测试,以确定这些优化是否确实使代码更快。(Fredrik Lundh在Needforspeed Sprint的贡献)

  • PyErr_NewException(name, base, dict) 现在可以接受一个基类元组作为它的 base 参数。(由乔治布兰德提供。)

  • 这个 PyErr_Warn() 现在不推荐使用发出警告的函数,而赞成使用 PyErr_WarnEx(category, message, 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特定的函数。

  • MaOSX --enable-universalsdk 开关已添加到 configure 将解释器编译为能够在PowerPC和Intel处理器上运行的通用二进制文件的脚本。(由罗纳德·奥索伦提供; bpo-2573

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

移植到python 2.5

本节列出了前面描述的可能需要更改代码的更改:

  • ASCII现在是模块的默认编码。如果一个模块包含带有8位字符的字符串文本,但没有编码声明,那么它现在就是一个语法错误。在Python2.4中,这引发了一个警告,而不是语法错误。

  • 以前, gi_frame 生成器的属性始终是帧对象。因为 PEP 342 第节中描述的更改 PEP 342:生成器的新功能 ,现在可以 gi_frame 成为 None .

  • 一个新的警告, UnicodeWarning ,在尝试比较使用默认ASCII编码无法转换为Unicode的Unicode字符串和8位字符串时触发。以前这样的比较会导致 UnicodeDecodeError 例外。

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

  • 类库: locale 模块的 format() 只要出现不超过一个%char的说明符,函数以前将接受任何字符串。在python 2.5中,参数必须正好是一个没有周围文本的%char说明符。

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

  • 类库: SimpleXMLRPCServerDocXMLRPCServer 课程现在有一个 rpc_paths 将XML-RPC操作约束到一组有限的URL路径的属性;默认值为仅允许 '/''/RPC2' . 设置 rpc_pathsNone 或者一个空元组禁用此路径检查。

  • 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_贝尔、Raymond Hettinger、Ralf W.Grosse Kunstleeve、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。