Python 2.5 的新特性 — Python 文档
Python 2.5 中的新功能
- 作者
- 是 库克林
本文解释了 Python 2.5 中的新功能。 Python 2.5 的最终版本定于 2006 年 8 月发布; PEP 356 描述了计划的发布时间表。
Python 2.5 中的变化是语言和库改进的有趣组合。 我认为,库的增强对 Python 的用户社区更重要,因为添加了几个广泛使用的包。 新模块包括用于 XML 处理的 ElementTree (xml.etree
)、SQLite 数据库模块 (sqlite
) 和用于调用 C 函数的 ctypes 模块。
语言变化具有中等意义。 添加了一些令人愉快的新功能,但其中大多数不是您每天都会使用的功能。 条件表达式最终使用新颖的语法添加到语言中; 请参阅部分 PEP 308:条件表达式 。 新的 'with' 语句将使编写清理代码更容易(PEP 343 部分:'with' 语句)。 现在可以将值传递到生成器中(第 PEP 342:新生成器功能 )。 导入现在可以作为绝对或相对可见(部分 PEP 328:绝对和相对导入 )。 一些异常处理的极端情况得到了更好的处理(PEP 341 部分:统一 try/except/finally)。 所有这些改进都是值得的,但它们是对一种或多种特定语言功能的改进; 它们都不是对 Python 语义的广泛修改。
除了语言和库的添加外,整个源代码树还进行了其他改进和错误修复。 通过 SVN 更改日志搜索发现,在 Python 2.4 和 2.5 之间应用了 353 个补丁并修复了 458 个错误。 (这两个数字都可能被低估了。)
本文并不试图成为新功能的完整规范; 相反,使用有用的示例简要介绍了更改。 有关完整的详细信息,您应该始终参考 https://docs.python.org 上的 Python 2.5 文档。 如果您想了解完整的实现和设计原理,请参阅特定新功能的 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 语言的语法中需要括号,但作为一种风格,我认为您应该始终使用它们。 考虑以下两个陈述:
# 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 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()
将名称、模块和文档字符串属性复制到包装函数,以便更容易理解包装函数内的回溯。 例如,你可以这样写:
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()
函数现在具有 requires
、provides
和 obsoletes
关键字参数。 当您使用 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
选项来对包进行 GPG 签名。
包上传是由 Martin von Löwis 和 Richard Jones 实现的。
也可以看看
- PEP 314 - Python 软件包的元数据 v1.1
- 由 AM 提出并编写的 PEP 库奇林、理查德·琼斯和弗雷德·德雷克; 由 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.main
和 pkg.string
子模块。
考虑 main.py
模块中的代码。 如果它执行语句 import string
会发生什么? 在 Python 2.4 及更早版本中,它会首先在包的目录中执行相对导入,找到 pkg/string.py
,将该文件的内容作为 pkg.string
模块导入,并且该模块绑定到pkg.main
模块命名空间中的名称 string
。
如果 pkg.string
是您想要的,那很好。 但是如果你想要 Python 的标准 string 模块呢? 没有干净的方法可以忽略 pkg.string
并寻找标准模块; 一般要看sys.modules
的内容,有点不干净。 Holger Krekel 的 py.std
包提供了一种从标准库 import py; py.std.string.join()
执行导入的更简洁的方法,但该包并非在所有 Python 安装上都可用。
阅读依赖于相对导入的代码也不太清楚,因为读者可能会混淆打算使用哪个模块,string 或 pkg.string
。 Python 用户很快就学会了不要在其包的子模块的名称中重复标准库模块的名称,但是您无法防止子模块的名称被用于在未来版本的 Python 中添加的新模块。
在 Python 2.5 中,您可以使用 from __future__ import absolute_import
指令将 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
中,这将从 pkg.string
导入 name1 和 name2 . 其他提前期从当前包的父级开始执行相对导入。 例如,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 - 进口:多线和绝对/相对
- PEP 由 Aahz 编写; 由 Thomas Wouters 实施。
- https://pylib.readthedocs.org/
- Holger Krekel 的 py 库,其中包含
py.std
包。
PEP 338:将模块作为脚本执行
Python 2.4 中添加的 -m 开关用于执行模块,因为脚本获得了更多功能。 该开关现在不是在 Python 解释器中以 C 代码实现,而是使用新模块 runpy 中的实现。
runpy 模块实现了更复杂的导入机制,因此现在可以在诸如 pychecker.checker
之类的包中运行模块。 该模块还支持替代导入机制,例如 zipimport 模块。 这意味着您可以将 .zip 存档的路径添加到 sys.path
,然后使用 -m 开关执行存档中的代码。
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
执行 block-1 中的代码。 如果代码引发异常,则测试各种 except 块:如果异常属于 Exception1
类,则执行 handler-1; 否则,如果它是 Exception2
类,则执行 handler-2,依此类推。 如果没有引发异常,则执行 else-block。
无论之前发生了什么,一旦代码块完成并处理了任何引发的异常,就会执行 final-block。 即使异常处理程序或 else-block 中出现错误并引发新异常,final-block 中的代码仍会运行。
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 表达式返回指定的 值 。 如果调用常规的 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
异常以终止迭代。 收到此异常时,生成器的代码必须引发GeneratorExit
或StopIteration
。 捕获GeneratorExit
异常并返回值是非法的,会触发RuntimeError
; 如果该函数引发了其他一些异常,则该异常将传播给调用者。close()
在生成器被垃圾回收时也会被 Python 的垃圾回收器调用。如果您需要在发生
GeneratorExit
时运行清理代码,我建议使用try: ... finally:
套件而不是捕获GeneratorExit
。
这些变化的累积效应是将生成者从信息的单向生产者转变为生产者和消费者。
生成器也变成了 协程 ,一种更通用的子程序形式。 子程序在一个点进入并在另一个点退出(函数的顶部,和一个 return 语句),但是协程可以在许多不同的点进入、退出和恢复(yield 声明)。 我们必须找出在 Python 中有效使用协程的模式。
添加 close()
方法有一个不明显的副作用。 close()
在生成器被垃圾收集时被调用,所以这意味着生成器的代码在生成器被销毁之前有最后一次运行的机会。 这最后的机会意味着现在可以保证生成器中的 try...finally
语句可以工作; finally 子句现在总是有机会运行。 因此,不能将 yield 语句与 try...finally
套件混合使用的语法限制已被删除。 这似乎是一些语言琐事,但实际上需要使用生成器和 try...finally
来实现 PEP 343 描述的 with 语句。 我将在下一节中查看这个新语句。
此更改的另一个更深奥的效果是:以前,生成器的 gi_frame
属性始终是框架对象。 一旦发电机耗尽,现在 gi_frame
有可能变成 None
。
也可以看看
- PEP 342 - 通过增强生成器的协程
PEP 由 Guido van Rossum 和 Phillip J. 编写。 艾比; 由 Phillip J 实施。 艾比。 包括一些将生成器用作协程的更巧妙用途的示例。
这些功能的早期版本是在 Raymond Hettinger 的 PEP 288 和 Samuele Pedroni 的 PEP 325 中提出的。
- https://en.wikipedia.org/wiki/Coroutine
协程的维基百科条目。
- 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__()
方法。
对象的 __enter__()
在执行 with-block 之前被调用,因此可以运行设置代码。 如果给出,它也可能返回绑定到名称 变量 的值。 (请注意 变量 是 不是 分配给 表达式 的结果。)
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 循环在块中途引发异常。
threading 模块的锁和条件变量也支持 'with' 语句:
lock = threading.Lock()
with lock:
# Critical section of code
...
在块执行之前获取锁,并且在块完成后总是释放锁。
decimal 模块中新的 localcontext()
函数可以轻松保存和恢复当前十进制上下文,它封装了计算所需的精度和舍入特性:
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__()
方法仍会被调用,但 type、value 和 traceback[ X136X] 都是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
为假,所以会自动重新引发异常。 如果您愿意,可以更明确地在标记位置添加 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 模块提供了一些函数和装饰器,这些函数和装饰器对于编写与 'with' 语句一起使用的对象很有用。
装饰器称为 contextmanager()
,它允许您编写单个生成器函数而不是定义新类。 生成器应该只产生一个值。 直到 yield 的代码将作为 __enter__()
方法执行,产生的值将是该方法的返回值,该值将绑定到 'with[ X184X]' 语句的 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 显示了为“with”语句生成的代码,这有助于了解该语句的工作原理。
contextlib 模块的文档。
PEP 352:作为新式类的例外
异常类现在可以是新式类,而不仅仅是经典类,内置 Exception
类和所有标准内置异常(NameError
、ValueError
、等)现在是新式类。
异常的继承层次结构已重新排列。 2.5中,继承关系为:
BaseException # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
|- (all other current built-in exceptions)
进行这种重新排列是因为人们通常希望捕获所有指示程序错误的异常。 KeyboardInterrupt
和 SystemExit
不是错误,但通常代表显式操作,例如用户点击 Control-C 或代码调用 sys.exit( )。 一个裸 except:
将捕获所有异常,因此您通常需要列出 KeyboardInterrupt
和 SystemExit
以重新提高它们。 通常的模式是:
try:
...
except (KeyboardInterrupt, SystemExit):
raise
except:
# Log error...
# Continue running program...
在 Python 2.5 中,您现在可以编写 except Exception
来实现相同的结果,捕获通常指示错误的所有异常,但单独留下 KeyboardInterrupt
和 SystemExit
。 与以前的版本一样,一个裸 except:
仍然可以捕获所有异常。
Python 3.0 的目标是要求任何作为异常引发的类派生自 BaseException
或 BaseException
的某些后代,并且 Python 2.x 系列的未来版本可能会开始强制执行此约束. 因此,我建议您现在就开始让所有的异常类派生自 Exception
。 有人建议应该在 Python 3.0 中删除裸 except:
表单,但 Guido van Rossum 尚未决定是否这样做。
将字符串作为异常引发,如语句 raise "Error occurred"
中,在 Python 2.5 中已弃用,并将触发警告。 目的是能够在几个版本中删除字符串异常功能。
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 编译器使用——参见 http://www.unix.org/version2/whatsnew/lp64_wp.html 进行讨论——但最常见的是可用模型将 int
保留为 32 位。)
2147483647 项的限制在 32 位平台上并不重要,因为在达到长度限制之前您将耗尽内存。 每个列表项都需要一个指针的空间,它是 4 个字节,加上一个 PyObject 表示该项目的空间。 2147483647*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
X146X] 使它们返回 Py_ssize_t
。
PEP 353 有一个关于转换指南的部分,扩展作者应该阅读以了解支持 64 位平台。
PEP 357:'__index__' 方法
NumPy 开发人员遇到了一个问题,只能通过添加一个新的特殊方法 __index__()
来解决。 使用切片表示法时,如 [start:stop:step]
,start、stop 和 step 索引的值必须全部为整数或长整数整数。 NumPy 定义了多种专门的整数类型,对应于 8、16、32 和 64 位的无符号和有符号整数,但是没有办法表明这些类型可以用作切片索引。
切片不能只使用现有的 __int__()
方法,因为该方法也用于实现对整数的强制转换。 如果切片使用 __int__()
,浮点数也将成为合法的切片索引,这显然是一种不受欢迎的行为。
相反,添加了一个名为 __index__()
的新特殊方法。 它不接受任何参数并返回一个整数,给出要使用的切片索引。 例如:
class C:
def __index__ (self):
return self.value
返回值必须是 Python 整数或长整数。 解释器将检查返回的类型是否正确,如果不满足此要求,则引发 TypeError
。
相应的 nb_index
槽被添加到 C 级 PyNumberMethods 结构中,让 C 扩展实现这个协议。 PyNumber_Index(obj)
可用于扩展代码中调用 __index__()
函数并检索其结果。
其他语言更改
以下是 Python 2.5 对核心 Python 语言所做的所有更改。
dict 类型有一个新的钩子,用于在字典中不包含键时让子类提供默认值。 当未找到键时,将调用字典的
__missing__(key)
方法。 这个钩子用于在 collections 模块中实现新的defaultdict
类。 以下示例定义了一个字典,该字典为任何缺失的键返回零: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 元组,但从字符串的末尾开始搜索;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')
(根据 Raymond Hettinger 的建议由 Fredrik Lundh 实施。)
字符串类型的
startswith()
和endswith()
方法现在接受要检查的字符串元组。def is_image_file (filename): return filename.endswith(('.gif', '.jpg', '.tiff'))
(根据 Tom Lynn 的建议,由 Georg Brandl 实施。)
min() 和 max() 内置函数获得了一个
key
关键字参数,类似于sort()
的key
参数]。 这个参数提供了一个函数,它接受一个参数,并为列表中的每个值调用; 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)
(由 Steven Bethard 和 Raymond Hettinger 提供。)
两个新的内置函数 any() 和 all() 评估迭代器是否包含任何真值或假值。 any() 如果迭代器返回的任何值为真,则返回 True; 否则将返回 False。 all() 仅当迭代器返回的所有值都评估为真时才返回 True。 (由 Guido van Rossum 建议,由 Raymond Hettinger 实施。)
类的
__hash__()
方法的结果现在可以是长整数或常规整数。 如果返回一个长整数,则采用该值的散列。 在早期版本中,散列值需要是一个常规整数,但在 2.5 中,内置的 id() 被更改为始终返回非负数,用户似乎经常使用 [ X194X] 在__hash__()
方法中(尽管不鼓励这样做)。ASCII 现在是模块的默认编码。 如果模块包含具有 8 位字符的字符串文字但没有编码声明,则现在是语法错误。 在 Python 2.4 中,这触发了警告,而不是语法错误。 有关如何声明模块的编码,请参阅 PEP 263; 例如,您可以在源文件顶部附近添加如下一行:
# -*- coding: latin1 -*-
当您尝试比较 Unicode 字符串和无法使用默认 ASCII 编码转换为 Unicode 的 8 位字符串时,会触发新警告
UnicodeWarning
。 比较结果为假:>>> 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 以记录所有搜索到的路径。 在 Python 2.5 中,当导入将目录作为包提取但未找到__init__.py
时,会触发新的ImportWarning
警告。 默认情况下,此警告会被静默忽略; 在运行 Python 可执行文件时提供 -Wd 选项以显示警告消息。 (由托马斯·沃特斯实施。)类定义中的基类列表现在可以为空。 例如,这现在是合法的:
class C(): pass
(由布雷特·坎农实施。)
交互式解释器更改
在交互式解释器中,quit
和 exit
长期以来一直是字符串,因此新用户在尝试退出时会得到一些有用的消息:
>>> quit
'Use Ctrl-D (i.e. EOF) to exit.'
在 Python 2.5 中,quit
和 exit
现在是仍然生成自身字符串表示的对象,但也是可调用的。 尝试 quit()
或 exit()
的新手现在将按预期退出解释器。 (由 Georg Brandl 实施。)
Python 可执行文件现在接受标准的长选项 --help 和 --version; 在 Windows 上,它还接受 /? 选项以显示帮助消息。 (由 Georg Brandl 实施。)
优化
2006 年 5 月 21 日至 28 日在冰岛雷克雅未克举行的 NeedForSpeed sprint 活动中开发了一些优化。 冲刺专注于提高 CPython 实现的速度,由 EWT LLC 资助,并得到 CCP Games 的本地支持。 在此 sprint 中添加的那些优化在以下列表中特别标记。
- 当它们在 Python 2.4 中被引入时,内置的 set 和 frozenset 类型建立在 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 贡献,并在 NeedForSpeed sprint 中承诺。)- 现在混合使用
for line in file
迭代文件并调用文件对象的read()
/readline()/readlines()
方法是非法的。 迭代使用内部缓冲区,而read*()
方法不使用该缓冲区。 相反,它们会在缓冲区后面返回数据,导致数据出现乱序。 混合迭代和这些方法现在将从read*()
方法触发ValueError
。 (由托马斯·沃特斯实施。) - struct 模块现在将结构格式字符串编译为内部表示并缓存此表示,从而产生 20% s 加速。 (由 Bob Ippolito 在 NeedForSpeed sprint 中提供。)
- re 模块通过切换到 Python 的分配器函数而不是系统的
malloc()
和free()
获得了 1 或 2% s 加速。 (由 Jack Diederich 在 NeedForSpeed sprint 中提供。) - 代码生成器的窥孔优化器现在在表达式中执行简单的常量折叠。 如果您编写类似
a = 2+3
的代码,代码生成器将进行算术运算并生成对应于a = 5
的代码。 (由 Raymond Hettinger 提出并实施。) - 函数调用现在更快,因为代码对象现在将最近完成的帧(“僵尸帧”)保存在代码对象的内部字段中,在下次调用代码对象时重用它。 (Michael Hudson 的原始补丁,由 Armin Rigo 和 Richard Jones 修改;在 NeedForSpeed sprint 中提交。)Frame 对象也稍微小一些,这可能会改善缓存局部性并稍微减少内存使用。 (尼尔·诺维茨供稿。)
- Python 的内置异常现在是新式类,这一变化大大加快了实例化速度。 因此,Python 2.5 中的异常处理比 2.4 高 30% f aster。 (由 Richard Jones、Georg Brandl 和 Sean Reifschneider 在 NeedForSpeed sprint 中提供。)
- 导入现在缓存尝试的路径,记录它们是否存在,以便解释器在启动时减少
open()
和stat()
调用。 (由 Martin von Löwis 和 Georg Brandl 提供。)
新增、改进和删除的模块
标准库在 Python 2.5 中获得了许多增强功能和错误修复。 这是最显着更改的部分列表,按模块名称的字母顺序排序。 请查阅源代码树中的 Misc/NEWS
文件以获取更完整的更改列表,或查看 SVN 日志以获取所有详细信息。
audioop模块现在支持a-LAW编码,并且改进了u-LAW编码的代码。 (拉尔斯·伊米施供稿。)
codecs 模块获得了对增量编解码器的支持。
codec.lookup()
函数现在返回CodecInfo
实例而不是元组。CodecInfo
实例表现得像一个 4 元组以保持向后兼容性,但也具有属性encode
、decode
、incrementalencoder
、incrementaldecoder
、streamwriter
和streamreader
。 增量编解码器可以在多个块中接收输入并产生输出; 输出与将整个输入馈送到非增量编解码器相同。 有关详细信息,请参阅 codecs 模块文档。 (由 Walter Dörwald 设计和实施。)collections 模块获得了一个新类型,
defaultdict
,它是标准 dict 类型的子类。 新类型的行为大多类似于字典,但在键不存在时构造一个默认值,自动将其添加到字典中以获取请求的键值。defaultdict
的构造函数的第一个参数是一个工厂函数,每当请求键但未找到时就会调用该函数。 这个工厂函数不接收任何参数,因此您可以使用内置类型构造函数,例如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']}
(由吉多·范罗苏姆提供。)
collections 模块提供的
deque
双端队列类型现在有一个remove(value)
方法,可以删除队列中第一次出现的 value,如果找不到值,则提高ValueError
。 (雷蒙德·赫廷格供稿。)新模块:contextlib 模块包含与新的 'with' 语句一起使用的辅助函数。 有关此模块的更多信息,请参阅 上下文库模块 部分。
新模块:cProfile 模块是现有 profile 模块的 C 实现,其开销要低得多。 该模块的界面与 profile 相同:您运行
cProfile.run('main()')
来分析函数,可以将分析数据保存到文件等。 目前尚不清楚 Hotshot 分析器(它也是用 C 编写的但与 profile 模块的接口不匹配)是否会在 Python 的未来版本中继续维护。 (由 Armin Rigo 提供。)此外,用于分析分析器测量的数据的 pstats 模块现在支持通过向
Stats
构造函数提供 stream 参数来将输出定向到任何文件对象。 (由跳过蒙塔纳罗提供。)csv 模块以逗号分隔值格式解析文件,获得了一些增强功能和一些错误修正。 您现在可以通过调用
csv.field_size_limit(new_limit)
函数来设置字段的最大大小(以字节为单位); 省略 new_limit 参数将返回当前设置的限制。reader
类现在有一个line_num
属性,用于计算从源读取的物理行数; 记录可以跨越多条物理线,因此line_num
与读取的记录数不同。CSV 解析器现在对多行引用字段更加严格。 以前,如果一行在带引号的字段内结束而没有终止换行符,则会在返回的字段中插入换行符。 当读取字段中包含回车符的文件时,此行为会导致问题,因此代码已更改为在不插入换行符的情况下返回字段。 因此,如果嵌入在字段中的换行符很重要,则应以保留换行符的方式将输入拆分为多行。
(由跳过蒙塔纳罗和安德鲁麦克纳马拉提供。)
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')
difflib 模块中的
SequenceMatcher.get_matching_blocks()
方法现在保证返回描述匹配子序列的最小块列表。 以前,该算法偶尔会将匹配元素块分成两个列表条目。 (由蒂姆彼得斯增强。)doctest 模块获得了一个
SKIP
选项,可以完全阻止示例执行。 这适用于作为读者使用示例而非实际测试用例的代码片段。encoding 参数已添加到
testfile()
函数和DocFileSuite
类以指定文件的编码。 这使得在包含在文档字符串中的测试中更容易使用非 ASCII 字符。 (由比约恩·蒂莱纽斯提供。)email 软件包已更新至 4.0 版。 (由巴里华沙提供。)
fileinput 模块变得更加灵活。 现在支持 Unicode 文件名,默认为
"r"
的 mode 参数已添加到 input() 函数中,以允许以二进制或 通用格式打开文件换行符 模式。 另一个新参数 openhook 允许您使用除 open() 之外的函数来打开输入文件。 一旦您对文件集进行迭代,FileInput
对象的新fileno()
将返回当前打开文件的文件描述符。 (由 Georg Brandl 提供。)在 gc 模块中,新的
get_count()
函数返回一个 3 元组,其中包含三个 GC 代的当前收集计数。 这是垃圾收集器的记帐信息; 当这些计数达到指定的阈值时,将进行垃圾收集扫描。 现有的 gc.collect() 函数现在采用可选的 generation 参数 0、1 或 2 来指定要收集的世代。 (由巴里华沙提供。)heapq 模块中的
nsmallest()
和nlargest()
函数现在支持key
关键字参数,类似于 min()[ X155X]/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']
(雷蒙德·赫廷格供稿。)
itertools.islice() 函数现在接受
None
作为开始和步骤参数。 这使它与切片对象的属性更加兼容,因此您现在可以编写以下内容:s = slice(5) # Create slice object itertools.islice(iterable, s.start, s.stop, s.step)
(雷蒙德·赫廷格供稿。)
修改了 locale 模块中的 format() 函数,并添加了两个新函数,
format_string()
和currency()
。format() 函数的 val 参数以前可以是字符串,只要出现不超过一个 %char 说明符; 现在参数必须正好是一个 %char 说明符,没有周围的文本。 还添加了一个可选的 monetary 参数,如果
True
,将使用区域设置的规则来格式化货币,以在三位数组之间放置分隔符。要使用多个 %char 说明符格式化字符串,请使用新的
format_string()
函数,其工作方式类似于 format(),但也支持将 %char 说明符与任意文本混合使用。还添加了一个新的
currency()
函数,可根据当前语言环境的设置格式化数字。(由 Georg Brandl 提供。)
mailbox 模块进行了大规模重写,以添加除了读取邮箱之外还可以修改邮箱的功能。 一组新的类,包括
mbox
、MH
和Maildir
用于读取邮箱,并有一个add(message)
方法来添加消息,remove(key)
删除邮件,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)
(由格雷戈里 K. 约翰逊。 资金由 Google 2005 Summer of Code 提供。)
新模块:msilib 模块允许创建 Microsoft 安装程序
.msi
文件和 CAB 文件。 还包括对读取.msi
数据库的一些支持。 (由 Martin von Löwis 提供。)nis 模块现在通过向 nis.match() 和 nis.maps 提供 domain 参数来支持访问系统默认域以外的域() 函数。 (本·贝尔供稿。)
operator 模块的
itemgetter()
和attrgetter()
函数现在支持多个字段。 诸如operator.attrgetter('a', 'b')
之类的调用将返回一个检索a
和b
属性的函数。 将此新功能与sort()
方法的key
参数相结合,可以让您轻松地使用多个字段对列表进行排序。 (雷蒙德·赫廷格供稿。)optparse 模块已更新到 Optik 库的 1.5.1 版。
OptionParser
类获得了一个epilog
属性,一个将在帮助消息后打印的字符串,以及一个用于中断对象创建的引用循环的destroy()
方法。 (由格雷格·沃德提供。)os 模块经历了几次更改。
stat_float_times
变量现在默认为 true,这意味着 os.stat() 现在将以浮点数形式返回时间值。 (这并不一定意味着 os.stat() 将返回精确到几分之一秒的时间;并非所有系统都支持这种精度。)添加了名为 os.SEEK_SET、os.SEEK_CUR 和 os.SEEK_END 的常量; 这些是 os.lseek() 函数的参数。 用于锁定的两个新常量是 os.O_SHLOCK 和 os.O_EXLOCK。
添加了两个新功能,
wait3()
和wait4()
。 它们类似于waitpid()
函数,它等待子进程退出并返回进程 ID 及其退出状态的元组,但wait3()
和wait4()
返回附加信息.wait3()
不接受进程 ID 作为输入,因此它等待任何子进程退出并返回 process-id, exit-status 的 3 元组], resource-usage 从 resource.getrusage() 函数返回。wait4(pid)
确实需要一个进程 ID。 (由乍得 J. 施罗德。)在 FreeBSD 上,os.stat() 函数现在以纳秒分辨率返回时间,并且返回的对象现在具有
st_gen
和st_birthtime
。 如果平台支持,st_flags
属性也可用。 (由 Antti Louko 和 Diego Pettenò 提供。)pdb 模块提供的 Python 调试器现在可以存储到达断点并停止执行时要执行的命令列表。 创建断点 #1 后,输入
commands 1
并输入要执行的一系列命令,以end
结束列表。 命令列表可以包括恢复执行的命令,例如continue
或next
。 (由 Grégoire Dooms 提供。)pickle 和 cPickle 模块不再接受来自
__reduce__()
方法的返回值None
; 该方法必须返回一个参数元组。 返回None
的功能在 Python 2.4 中已被弃用,因此完成了该功能的删除。pkgutil 模块包含用于查找包的各种实用功能,经过增强以支持 PEP 302 的导入挂钩,现在也适用于存储在 ZIP 格式档案中的包。 (菲利普·J。 伊比。)
Marc-André Lemburg 的 pybench 基准测试套件现在包含在
Tools/pybench
目录中。 pybench 套件是对常用pystone.py
程序的改进,因为 pybench 提供了对解释器速度的更详细的测量。 它对函数调用、元组切片、方法查找和数字操作等特定操作进行计时,而不是像pystone.py
那样执行许多不同的操作并将结果减少到单个数字。pyexpat
模块现在使用 Expat 解析器的 2.0 版。 (由特伦特·米克提供。)Queue 模块提供的 Queue 类获得了两个新方法。
join()
阻塞直到队列中的所有项目都被检索到并且项目的所有处理工作都已经完成。 工作线程调用另一个新方法task_done()
,以表示项目的处理已完成。 (雷蒙德·赫廷格供稿。)旧的
regex
和regsub
模块从 Python 2.0 开始就被弃用了,终于被删除了。 其他删除的模块:statcache
、tzparse
、whrandom
。还删除了:删除了
lib-old
目录,其中包括dircmp
和ni
等古老模块。lib-old
不在默认的sys.path
上,因此除非您的程序明确将目录添加到sys.path
,否则此删除不应影响您的代码。rlcompleter 模块不再依赖于导入 readline 模块,因此现在可以在非 Unix 平台上运行。 (来自 Robert Kiendl 的补丁。)
SimpleXMLRPCServer 和 DocXMLRPCServer 类现在有一个
rpc_paths
属性,它将 XML-RPC 操作限制为一组有限的 URL 路径; 默认是只允许'/'
和'/RPC2'
。 将rpc_paths
设置为None
或空元组将禁用此路径检查。由于 Philippe Biondi 的补丁,socket 模块现在支持 Linux 上的
AF_NETLINK
套接字。 Netlink 套接字是一种 Linux 特定的机制,用于在用户空间进程和内核代码之间进行通信; 关于它们的介绍性文章位于 https://www.linuxjournal.com/article/7356。 在 Python 代码中,netlink 地址表示为 2 个整数的元组,(pid, group_mask)
。套接字对象上的两个新方法
recv_into(buffer)
和recvfrom_into(buffer)
将接收到的数据存储在支持缓冲区协议的对象中,而不是将数据作为字符串返回。 这意味着您可以将数据直接放入数组或内存映射文件中。套接字对象还获得了
getfamily()
、gettype()
和getproto()
访问器方法来检索套接字的系列、类型和协议值。新模块:spwd 模块提供了在支持影子密码的系统上访问影子密码数据库的功能。
struct 现在更快,因为它使用
pack()
和unpack()
方法将格式字符串编译为Struct
对象。 这类似于 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
对象由 Bob Ippolito 在 NeedForSpeed sprint 中实现。 Martin Blais 添加了对缓冲区对象的支持,也在 NeedForSpeed 冲刺中。)Python 开发人员在 2.5 开发过程中从 CVS 切换到 Subversion。 有关确切构建版本的信息可作为
sys.subversion
变量,(interpreter-name, branch-name, revision-range)
的 3 元组。 例如,在撰写我的 2.5 副本时,报告的是('CPython', 'trunk', '45313:45315')
。此信息也可通过 Py_GetBuildInfo() 函数用于 C 扩展,该函数返回如下所示的构建信息字符串:
"trunk:45355:45356M, Apr 13 2006, 07:42:19"
。 (由巴里华沙提供。)另一个新函数 sys._current_frames() 返回所有正在运行的线程的当前堆栈帧作为字典,将线程标识符映射到调用该函数时该线程中当前处于活动状态的最顶层堆栈帧。 (由蒂姆·彼得斯提供。)
tarfile 模块中的
TarFile
类现在有一个extractall()
方法,可将存档中的所有成员提取到当前工作目录中。 也可以将不同的目录设置为提取目标,并仅解压缩存档成员的子集。现在可以使用模式
'r|*'
自动检测用于以流模式打开的 tarfile 的压缩。 (拉尔斯·古斯塔贝尔供稿。)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 生成通用唯一标识符 (UUID)。 RFC 定义了几个不同的 UUID 版本,这些版本是从起始字符串、系统属性或纯随机生成的。 该模块包含一个
UUID
类和名为uuid1()
、uuid3()
、uuid4()
和uuid5()
的函数,用于生成不同版本的 UUID。 (RFC 4122 中未指定第 2 版 UUID,并且此模块不支持。)>>> 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')
(由 Ka-Ping Yee 提供。)
weakref 模块的
WeakKeyDictionary
和WeakValueDictionary
类型获得了迭代字典中包含的弱引用的新方法。iterkeyrefs()
和keyrefs()
方法被添加到WeakKeyDictionary
,itervaluerefs()
和valuerefs()
被添加到WeakValueDictionary
。 (供稿人弗雷德 L。 小德雷克)webbrowser 模块获得了许多增强功能。 它现在可以用作带有
python -m webbrowser
的脚本,以 URL 作为参数; 有许多开关可以控制行为(-n
用于新浏览器窗口,-t
用于新选项卡)。 添加了新的模块级函数open_new()
和open_new_tab()
以支持此功能。 模块的 open() 函数支持附加功能,即 autoraise 参数,该参数指示是否在可能的情况下提升打开的窗口。 许多其他浏览器已添加到支持列表中,例如 Firefox、Opera、Konqueror 和 elinks。 (由 Oleg Broytmann 和 Georg Brandl 提供。)xmlrpclib 模块现在支持为 XML-RPC 日期类型返回 datetime 对象。 将
use_datetime=True
提供给loads()
功能或Unmarshaller
类以启用此功能。 (由跳过蒙塔纳罗提供。)zipfile 模块现在支持该格式的 ZIP64 版本,这意味着 .zip 存档现在可以大于 4 GiB,并且可以包含大于 4 GiB 的单个文件。 (罗纳德·奥索伦供稿。)
zlib 模块的
Compress
和Decompress
对象现在支持 copy() 方法,该方法复制对象的内部状态并返回一个新的 [ X165X] 或Decompress
对象。 (由克里斯·阿特利提供。)
ctypes 包
由 Thomas Heller 编写的 ctypes 包已添加到标准库中。 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 函数将修改内存区域时,不应将 c_char_p()
与 Python 字符串一起使用,因为 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
对象。 这个对象在调用函数之前不会释放全局解释器锁,因为在调用解释器的代码时必须持有锁。 有一个 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 而不是扩展模块访问的库之上编写 Python 包装器,现在 ctypes 包含在核心 Python 中。
元素树包
Fredrik Lundh 用于处理 XML 的 ElementTree 库的一个子集已添加到标准库中,名称为 xml.etree
。 可用的模块是 ElementTree 1.2.6 中的 ElementTree
、ElementPath
和 ElementInclude
。 cElementTree
加速器模块也包括在内。
本节的其余部分将简要概述使用 ElementTree。 ElementTree 的完整文档可在 http://effbot.org/zone/element-index.htm 获得。
ElementTree 将 XML 文档表示为元素节点树。 文档的文本内容存储为 text
和 tail
的属性(这是 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 个到第 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。 |
注释和处理指令也表示为 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 接口的部分描述。 请阅读软件包的官方文档以获取更多详细信息。
哈希库包
一个新的 hashlib 模块,由 Gregory P. 编写。 已添加 Smith,以替换 md5 和 sha 模块。 hashlib 添加了对其他安全哈希(SHA-224、SHA-256、SHA-384 和 SHA-512)的支持。 如果可用,该模块使用 OpenSSL 来实现算法的快速平台优化实现。
旧的 md5 和 sha 模块仍然作为 hashlib 的包装器存在以保持向后兼容性。 新模块的界面与旧模块的界面非常接近,但并不完全相同。 最显着的区别是用于创建新散列对象的构造函数的命名不同。
# 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
一旦创建了哈希对象,其方法与之前相同:update(string)
将指定字符串哈希到当前摘要状态,digest()
和 hexdigest()
返回摘要值作为二进制字符串或十六进制数字字符串,copy() 返回具有相同摘要状态的新散列对象。
sqlite3 包
pysqlite 模块 (http://www.pysqlite.org),SQLite 嵌入式数据库的包装器,已添加到标准库中,包名称为 sqlite3。
SQLite 是一个 C 库,它提供了一个轻量级的基于磁盘的数据库,不需要单独的服务器进程,并允许使用 SQL 查询语言的非标准变体访问数据库。 某些应用程序可以使用 SQLite 进行内部数据存储。 还可以使用 SQLite 对应用程序进行原型设计,然后将代码移植到更大的数据库,例如 PostgreSQL 或 Oracle。
pysqlite 由 Gerhard Häring 编写,并提供符合 PEP 249 描述的 DB-API 2.0 规范的 SQL 接口。
如果您自己编译 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 由 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()
构建和 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]
还没有为 AST 代码编写官方文档,但 PEP 339 讨论了设计。 要开始了解代码,请阅读
Parser/Python.asdl
中各种 AST 节点的定义。 Python 脚本读取此文件并在Include/Python-ast.h
中生成一组 C 结构定义。 在Include/pythonrun.h
中定义的PyParser_ASTFromString()
和PyParser_ASTFromFile()
以 Python 源代码作为输入并返回表示内容的 AST 的根。 然后可以通过PyAST_Compile()
将这个 AST 转换为代码对象。 有关更多信息,请阅读源代码,然后在 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()[X] ]、PyObject_Realloc() 和 PyObject_Free() 是另一个应该用于创建 Python 对象的家族。
以前这些不同的家族都归结为平台的
malloc()
和free()
功能。 这意味着如果出现错误并使用PyMem()
函数分配内存但使用 PyObject() 函数释放它并不重要。 随着 2.5 对 obmalloc 的更改,这些系列现在做不同的事情,不匹配可能会导致段错误。 您应该使用 Python 2.5 仔细测试您的 C 扩展模块。内置的集合类型现在有一个官方的 C API。 调用 PySet_New() 和 PyFrozenSet_New() 创建一个新集合,PySet_Add() 和 PySet_Discard() 添加和删除元素, 和 PySet_Contains() 和 PySet_Size() 来检查集合的状态。 (雷蒙德·赫廷格供稿。)
C 代码现在可以通过调用 Py_GetBuildInfo() 函数来获取有关 Python 解释器的确切修订的信息,该函数返回如下所示的构建信息字符串:
"trunk:45355:45356M, Apr 13 2006, 07:42:19"
。 (由巴里华沙提供。)两个新宏可用于指示当前文件本地的 C 函数,以便可以使用更快的调用约定。
Py_LOCAL(type)
将函数声明为返回指定 type 的值并使用快速调用限定符。Py_LOCAL_INLINE(type)
做同样的事情并且还请求函数被内联。 如果在包含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 提供;:issue:`2573`。) - Windows:不再支持将
.dll
作为扩展模块的文件扩展名。.pyd
现在是唯一要搜索的文件扩展名。
移植到 Python 2.5
本节列出了可能需要更改代码的先前描述的更改:
- ASCII 现在是模块的默认编码。 如果模块包含具有 8 位字符的字符串文字但没有编码声明,则现在是语法错误。 在 Python 2.4 中,这触发了警告,而不是语法错误。
- 以前,生成器的
gi_frame
属性始终是框架对象。 由于 PEP 342 更改在 PEP 342:新生成器功能 部分中描述,现在gi_frame
可以是 [ X154X]。 - 当您尝试比较 Unicode 字符串和无法使用默认 ASCII 编码转换为 Unicode 的 8 位字符串时,会触发新警告
UnicodeWarning
。 以前,此类比较会引发UnicodeDecodeError
异常。 - 库:csv 模块现在对多行引用字段更加严格。 如果您的文件包含嵌入在字段中的换行符,则输入应以保留换行符的方式拆分成行。
- 库:locale 模块的 format() 函数以前会接受任何字符串,只要不超过一个 %char 说明符出现。 在 Python 2.5 中,参数必须正好是一个 %char 说明符,没有周围的文本。
- 库:pickle 和 cPickle 模块不再接受来自
__reduce__()
方法的返回值None
; 该方法必须返回一个参数元组。 模块也不再接受已弃用的 bin 关键字参数。 - 库:SimpleXMLRPCServer 和 DocXMLRPCServer 类现在有一个
rpc_paths
属性,将 XML-RPC 操作限制为一组有限的 URL 路径; 默认是只允许'/'
和'/RPC2'
。 将rpc_paths
设置为None
或空元组将禁用此路径检查。 - 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. 埃比、拉尔斯·古斯塔贝尔、雷蒙德·赫廷格、拉尔夫·W. Grosse-Kunstleve、肯特·约翰逊、伊恩·洛、马丁·冯·洛维斯、弗雷德里克·伦德、安德鲁·麦克纳马拉、斯基普·蒙塔纳罗、古斯塔沃·尼迈耶、保罗·普雷斯科德、詹姆斯·普赖尔、迈克·罗夫纳、斯科特·魏卡特、巴里·华沙、托马斯·沃特斯。