What’s New in Python 2.5¶
作者: | 上午。 Kuchling |
---|
本文解释了Python 2.5中的新功能。Python 2.5的最终版本定于2006年8月发布; PEP 356描述计划的发布计划。
Python 2.5中的变化是语言和库改进的有趣组合。对于Python的用户社区来说,库增强将会更加重要,因为我添加了几个非常有用的包。新模块包括用于XML处理的ElementTree(xml.etree
),SQLite数据库模块(sqlite
)和用于调用C函数的ctypes
。
语言变化具有重要的意义。添加了一些愉快的新功能,但大多数是不是你会使用每一天的功能。最后,使用一种新颖的语法将条件表达式添加到语言中;请参见PEP 308: Conditional Expressions一节。新的with
语句将使编写清除代码更容易(第PEP 343: The ‘with’ statement)。现在可以将值传递到生成器(PEP 342: New Generator Features部分)。导入现在可以显示为绝对或相对(PEP 328: Absolute and Relative Imports部分)。更好地处理异常处理的一些角落情况(部分PEP 341: Unified try/except/finally)。所有这些改进是值得的,但它们是对一个特定语言功能的改进;它们都不是对Python语义的广泛修改。
除了语言和库添加,其他改进和错误修复在整个源代码树。通过SVN更改日志进行搜索,发现应用了353个修补程序,并在Python 2.4和2.5之间修复了458个错误。(这两个数字可能都是低估的。)
本文不试图成为新功能的完整规范;而是使用有用的示例简要介绍更改。有关详细信息,您应始终参考https://docs.python.org上有关Python 2.5的文档。如果您想了解完整的实现和设计理由,请参阅PEP了解特定的新功能。
欢迎对本文档提出意见,建议和错误报告;请通过电子邮件将其发送给作者或在Python错误跟踪器中打开一个错误。
PEP 308: Conditional Expressions¶
很长一段时间以来,人们一直在请求一种方式来写条件表达式,这些表达式返回值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
评估仍然像在现有的布尔表达式中一样延迟,因此评估的顺序跳过一个位。中间的条件表达式是计算的,而且只有条件为真时,true_value表达式才是计算。类似地,当条件为假时,false_value表达式仅为计算。
这种语法可能看起来很奇怪和后退;为什么条件进入表达式的中间,而不是在C的c ? x : y
?通过将新语法应用于标准库中的模块并查看结果代码如何读取来检查该决定。在许多使用条件表达式的情况下,一个值似乎是“常见情况”,一个值是“例外情况”,仅在不满足条件的较少场合使用。条件语法使这个模式有点更明显:
contents = ((doc + '\n') if doc else '')
我读取上面的语句作为含义“这里内容通常被赋予值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执行。第二个版本读得更好,在我看来,因为它清楚的是,分配总是执行和选择是在两个值之间。
包括括号的另一个原因:列表推导式和lambdas的几个奇数组合可能看起来像不正确的条件表达式。有关示例,请参见 PEP 308。如果你在你的条件表达式周围加括号,你不会遇到这种情况。
也可以看看
- PEP 308 - 条件表达式
- PEP由Guido van Rossum和Raymond D.Hettinger编写;由Thomas Wouters执行。
PEP 309: Partial Function Application¶
functools
模块旨在包含用于函数式编程的工具。
此模块中的一个有用的工具是partial()
函数。对于以函数式样编写的程序,有时需要构造已填充了某些参数的现有函数的变体。考虑一个Python函数f(a, b, c)
您可以创建一个等于f(1, t8)的新函数
。这被称为“部分功能应用”。g(b, c) > b, c)
partial()
接受参数(function, arg1, arg2, ... kwarg1 = value1, kwarg2 = value2)
。生成的对象是可调用的,所以您可以调用它来调用函数与填充的参数。
这里有一个小但实际的例子:
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()
将名称,模块和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: Metadata for Python Software Packages v1.1¶
Distutils添加了一些简单的依赖关系支持。setup()
现在有requires
,provides
和obsoletes
关键字参数。当使用sdist
命令构建源分发时,依赖性信息将记录在PKG-INFO
文件中。
另一个新的关键字参数为download_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.python.org上对Python包索引的另一个新增强功能是存储包的源和二进制归档。新的上传 Distutils命令会将包上传到存储库。
在上传包之前,您必须能够使用sdist Distutils命令构建分发。一旦有效,您可以运行python setup.py 上传
将您的软件包添加到PyPI存档。或者,您可以通过提供--sign
和--identity
选项对GPG进行GPG签名。
软件包上传由Martin vonLöwis和Richard Jones执行。
也可以看看
- PEP 314 - Python软件包v1.1的元数据
- PEP由A.M.提出和撰写。 Kuchling,Richard Jones和Fred Drake;由理查德·琼斯和弗雷德·德雷克执行。
PEP 328: Absolute and Relative Imports¶
PEP 328的较简单的部分在Python 2.4中实现:现在可以使用括号括起从从 ... import ...
语句,以便于导入许多不同的名称。
在Python 2.5中实现的更复杂的部分:导入模块可以指定为使用绝对或包相对导入。该计划是在将来的Python版本中将绝对导入作为默认值。
假设你有一个这样的包目录:
pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py
这定义了包含pkg.main
和pkg.string
子模块的名为pkg
的包。
请考虑main.py
模块中的代码。如果执行语句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.
这很好,如果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中,您可以使用来自 __ future __ import的将
指令。这个绝对导入行为将成为未来版本(可能是Python 2.7)中的默认行为。一旦绝对导入是默认值,import
absolute_importimport string
将始终找到标准库的版本。建议用户尽可能开始使用绝对导入,因此,最好从 pkg import 开始写入string
。
当使用从 ... 导入
向模块名称添加前导周期时,形成:
# Import names from pkg.string
from .string import name1, name2
# Import pkg.string
from . import string
这将导入相对于当前包的string
模块,因此在pkg.main
中,将导入name1和name2从pkg.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
Leading periods cannot be used with the import modname
form of the import statement, only the from ... import
form.
也可以看看
- PEP 328 - 导入:多行和绝对/相对
- PEP由Aahz编写;由Thomas Wouters执行。
- https://pylib.readthedocs.org/
- 由Holger Krekel提供的py库,它包含
py.std
包。
PEP 338: Executing Modules as Scripts¶
在Python 2.4中添加的-m
开关可以作为脚本执行模块,获得了更多的功能。而不是在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
块和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。
不管先前发生了什么,一旦代码块完成并且处理任何引发的异常,将执行最终块。即使异常处理程序或else-block中存在错误,并且出现新的异常,final-block中的代码仍会运行。
也可以看看
- PEP 341 - 统一try-except和try-finally
- PEP由Georg Brandl编写;由Thomas Lee执行。
PEP 342: New Generator Features¶
Python 2.5增加了一个将值传递到生成器的简单方法。如Python 2.3中所介绍的,生成器只产生输出;一旦生成器的代码被调用来创建迭代器,当它的执行被恢复时,没有办法将任何新的信息传递给函数。有时,传递一些信息的能力将是有用的。Hackish的解决方案包括使生成器的代码看一个全局变量,然后改变全局变量的值,或者传递一些可变对象,然后调用者修改。
要刷新您的基本生成器的记忆,这里有一个简单的例子:
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
表达式必须始终括号,除非它出现在顶级表达式在作业的右手边。This means you can write val = yield i
but have to use parentheses when there’s an operation, as in 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
实际上是必要的,以实现with
语句由PEP 343描述。我将在下面的部分看这个新的语句。
这种变化的另一个更深奥的效果:以前,生成器的gi_frame
属性总是一个框架对象。生成器耗尽后,gi_frame
现在可以为None
。
也可以看看
- PEP 342 - 通过增强生成器协议
PEP,由Guido van Rossum和Phillip J.Eby编写;由Phillip J. Eby执行。包括生成器作为协程的某些用户使用的例子。
这些特征的早期版本由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: The ‘with’ statement¶
'with
'语句澄清了以前使用try...finally
块的代码,以确保清除代码被执行。在本节中,我将讨论该语句,因为它通常会被使用。在下一节中,我将检查实现细节,并展示如何编写用于此语句的对象。
'with
'语句是一种新的控制流结构,其基本结构是:
with expression [as variable]:
with-block
表达式是计算,它应该导致一个对象支持上下文管理协议(即,具有__enter__()
和__exit__()
方法。
在执行with-block之前调用对象的__enter__()
,因此可以运行设置代码。它还可以返回绑定到名称变量的值(如果给出)。(请注意,变量是而不是指定表达式的结果。)
在执行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 t6 >。
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()
Writing Context Managers¶
在内部,'with
'语句是相当复杂。大多数人只会在现有对象中使用“with
”,因此不需要知道这些详细信息,因此如果您愿意,可以跳过本节的其余部分。新对象的作者需要了解底层实现的细节,并应继续阅读。
上下文管理协议的高级解释是:
- 表达式是计算,并应导致一个称为“上下文管理器”的对象。上下文管理器必须具有
__enter__()
和__exit__()
方法。 - 调用上下文管理器的
__enter__()
方法。返回的值分配给VAR。如果不存在'作为 VAR'
子句,则仅丢弃该值。 - 将执行BLOCK中的代码。
- 如果BLOCK引发异常,则
__ exit __(type, 值, traceback) 使用异常详细信息调用,由
方法的返回值控制是否重新引发异常:任何false值重新引发异常,并且sys.exc_info()
返回的相同值。True
将导致抑制异常。你很少想要抑制异常,因为如果你做包含'with
'的代码的作者永远不会意识到任何错误。 - 如果BLOCK没有引发异常,
__exit__()
方法仍然被调用,但类型,value和traceback都是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__()
方法很容易,只需要启动一个新的事务。对于这个应用程序,产生的游标对象将是一个有用的结果,所以方法将返回它。然后,用户可以将作为 光标
添加到其“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
The contextlib module¶
新的contextlib
模块提供了一些函数和装饰器,可用于编写用于“with
”语句的对象。
装饰器称为contextmanager()
,并允许您编写单个生成器函数,而不是定义新类。生成器应该只产生一个值。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. 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
模块还有一个嵌套(mgr1, mgr2, ...) t3 >函数组合了多个上下文管理器,因此您不需要编写嵌套的
在此示例中,单个“with
'语句。with
”语句都会启动数据库事务并获取线程锁定:
lock = threading.Lock()
with nested (db_transaction(db), lock) as (cursor, locked):
...
最后,closing(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: Exceptions as New-Style Classes¶
异常类现在可以是新式类,而不仅仅是经典类,内建Exception
类和所有标准内建异常(NameError
,ValueError
现在是新式的类。
异常的继承层次已经重新排列了一点。在2.5中,继承关系是:
BaseException # New in Python 2.5
|- KeyboardInterrupt
|- SystemExit
|- Exception
|- (all other current built-in exceptions)
这种重新排列是因为人们经常想捕获所有指示程序错误的异常。KeyboardInterrupt
and SystemExit
aren’t errors, though, and usually represent an explicit action such as the user hitting Control-C
or code calling sys.exit()
. 一个裸的except:
将捕获所有异常,因此您通常需要列出KeyboardInterrupt
和SystemExit
以重新提高它们。通常的模式是:
try:
...
except (KeyboardInterrupt, SystemExit):
raise
except:
# Log error...
# Continue running program...
In Python 2.5, you can now write except Exception
to achieve the same result, catching all the exceptions that usually indicate errors but leaving KeyboardInterrupt
and SystemExit
alone. 与以前的版本一样,裸机except:
仍然捕获所有异常。
Python 3.0的目标是要求作为异常引发的任何类从BaseException
派生或BaseException
的某个后代派生,并且Python 2.x系列中的将来版本可能开始以强制实施此约束。因此,我建议你开始使所有的异常类从Exception
派生。有人建议在Python 3.0中删除裸的except:
表单,但Guido van Rossum还没有决定是否这样做。
Raising of strings as exceptions, as in the statement raise "Error occurred"
, is deprecated in Python 2.5 and will trigger a warning. 目的是能够删除几个版本中的字符串异常功能。
也可以看看
- PEP 352 - 异常所需的超类
- PEP由Brett Cannon和Guido van Rossum编写;由Brett Cannon执行。
PEP 353: Using ssize_t as the index type¶
对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位用户的数量仍然相对较小。(In 5 or 10 years, we may all be on 64-bit machines, and the transition would be more painful then.)
此更改最有效地影响C扩展模块的作者。Python字符串和容器类型(如列表和元组)现在使用Py_ssize_t
来存储它们的大小。PyList_Size()
等函数现在返回Py_ssize_t
。因此,扩展模块中的代码可能需要将一些变量更改为Py_ssize_t
。
PyArg_ParseTuple()
和Py_BuildValue()
函数对Py_ssize_t
有一个新的转换代码n
。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 vonLöwis撰写和实施。
PEP 357: The ‘__index__’ method¶
NumPy开发人员有一个问题,只能通过添加一个新的特殊方法,__index__()
来解决。当在[start:stop:step]
中使用切片符号时,开始,停止和/ t4>索引必须是整数或长整数。NumPy定义了对应于8,16,32和64位的无符号和有符号整数的各种专用整数类型,但是没有办法表示这些类型可以用作片索引。
切片不能仅使用现有的__int__()
方法,因为该方法也用于实现对整数的强制。如果切片使用__int__()
,浮点数也将成为合法的切片索引,这显然是一种不良行为。
而是添加了一个名为__index__()
的新特殊方法。它不需要任何参数,并返回一个整数,给出要使用的slice索引。例如:
class C:
def __index__ (self):
return self.value
返回值必须是Python整数或长整数。解释器将检查返回的类型是否正确,如果不满足此要求,则引入TypeError
。
相应的nb_index
槽添加到C级PyNumberMethods
结构,以使C扩展实现此协议。可以在扩展代码中使用PyNumber_Index(obj)
来调用__index__()
函数并检索其结果。
也可以看看
- PEP 357 - 允许任何对象用于切片
- PEP由Travis Oliphant编写和实施。
Other Language Changes¶
这里是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)
也返回一个三元组,但开始从字符串的结尾搜索;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()
和max()
内建函数获得类似于key
参数的key
sort()
。此参数提供一个函数,它接受单个参数,并为列表中的每个值调用;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()
计算迭代器是否包含任何true或false值。any()
返回True
否则将返回False
。只有当迭代器计算返回的所有值都为真时,all()
才会返回True
。(由Guido van Rossum建议,由Raymond Hettinger实施。)类的
__hash__()
方法的结果现在可以是长整数或正整数。如果返回一个长整数,则取该值的哈希值。在早期版本中,散列值需要是正整数,但在2.5中,id()
内建被更改为始终返回非负数,用户通常似乎使用id(self)
在__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
选项。(由Thomas Wouters执行。)类定义中的基类的列表现在可以为空。例如,现在是合法的:
class C(): pass
(由Brett Cannon执行。)
Interactive Interpreter Changes¶
在交互式解释器中,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执行)
Optimizations¶
几个优化是在2006年5月21 - 28日在冰岛雷克雅未克举行的NeedForSpeed冲刺中开发的。这个sprint专注于CPython实现的速度提升,由EWT LLC和CCP Games的本地支持资助。在此冲刺中添加的优化在以下列表中特别标记。
- 当他们在Python 2.4中引入时,内建
set
和frozenset
类型是建立在Python的字典类型之上。在2.5中,内部数据结构已被定制用于实现集合,并且作为结果集将使用第三少的存储器并且稍快。(由Raymond Hettinger执行。) - 一些Unicode操作的速度,如查找子字符串,字符串拆分和字符映射编码和解码,已得到改进。(Substring搜索和分裂改进由Fredrik Lundh和Andrew Dalke在NeedForSpeed sprint中添加。角色地图由WalterDörwald和Martin vonLö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’sread()
/readline()
/readlines()
methods. Iteration使用内部缓冲区,read*()
方法不使用该缓冲区。相反,它们将返回缓冲区后面的数据,导致数据显示顺序不正确。混合迭代和这些方法现在将从read*()
方法中触发ValueError
。(由Thomas Wouters执行。) struct
模块现在将结构格式字符串编译为内部表示,并缓存此表示,从而产生20%的加速。(由Bob Ippolito在NeedForSpeed sprint提供。)- 通过切换到Python的分配器函数而不是系统的
malloc()
和free()
,re
模块获得1%(由Jack Diederich在NeedForSpeed冲刺中提供。) - 代码生成器的窥视孔优化器现在在表达式中执行简单的常量折叠。如果你写的东西像
a = 2 + 3
,代码生成器会做算术和产生代码对应于a = 5
。(由Raymond Hettinger提议和实施。) - 函数调用现在更快,因为代码对象现在在代码对象的内部字段中保留最近完成的帧(“僵尸帧”),在下一次调用代码对象时重用它。(原始补丁由Michael Hudson修改,由Armin Rigo和Richard Jones修改;承诺在NeedForSpeed冲刺)。帧对象也稍小,这可以提高缓存位置并且减少内存使用一点。(由Neal Norwitz提供)
- Python的内建异常现在是新式的类,这种变化大大加速了实例化。在Python 2.5中的异常处理因此比在2.4中快大约30%。(由Richard Jones,Georg Brandl和Sean Reifschneider在NeedForSpeed sprint提供。)
- 导入现在缓存尝试的路径,记录它们是否存在,以便解释器在启动时减少
open()
和stat()
。(供稿人:Martin vonLöwis和Georg Brandl。)
New, Improved, and Removed Modules¶
标准库在Python 2.5中接受了许多增强和错误修复。这里是最显着的变化的部分列表,按模块名称按字母顺序排序。请参阅源树中的Misc/NEWS
文件以获取更完整的更改列表,或查看SVN日志中的所有详细信息。
audioop
模块现在支持a-LAW编码,并且u-LAW编码的代码已得到改进。(供稿人:Lars Immisch。)codecs
模块获得了对增量编解码器的支持。codec.lookup()
函数现在返回一个CodecInfo
实例,而不是一个元组。CodecInfo
实例表现得像4元组以保持向后兼容性,但也具有属性encode
,decode
,incrementalencoder
,incrementaldecoder
,streamwriter
和streamreader
。增量编解码器可以接收输入并在多个块中产生输出;输出与将整个输入馈送到非增量编解码器的输出相同。有关详细信息,请参阅codecs
模块文档。(由WalterDö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']}
(供稿人:Guido van Rossum。)
collections
模块提供的deque
双端队列类型现在具有remove(value)
方法,用于删除值,如果未找到该值,则提高ValueError
。(由Raymond Hettinger提供)新模块:
contextlib
模块包含用于新的'with
'语句的帮助函数。有关此模块的更多信息,请参见The contextlib module一节。New module: The
cProfile
module is a C implementation of the existingprofile
module that has much lower overhead. 模块的接口与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 theStats
constructor. (供稿:Skip Montanaro。)The
csv
module, which parses files in comma-separated value format, received several enhancements and a number of bugfixes. 现在,您可以通过调用csv.field_size_limit(new_limit)
函数来设置字段的最大大小(以字节为单位);省略new_limit参数将返回当前设置的限制。reader
类现在具有line_num
属性,用于计算从源读取的物理行数;记录可以跨越多个物理行,因此line_num
与读取的记录数不同。现在CSV解析器对于多行引用的字段更加严格。以前,如果行在带有终止换行符的带引号字段中结束,则将在返回字段中插入换行符。当读取包含字段内的回车字符的文件时,此行为会导致问题,因此更改代码以返回字段而不插入换行符。因此,如果嵌入字段中的换行符很重要,则应以保留换行符的方式将输入拆分成行。
(供稿:Skip Montanaro和Andrew McNamara。)
datetime
模块中的datetime
类现在具有strptime(string, 格式) t6 >解析日期字符串的方法,由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()
方法现在保证返回描述匹配子序列的块的最小列表。以前,算法偶尔会将匹配元素块分成两个列表条目。(Tim Peters的增强)doctest
模块获得了一个SKIP
选项,使得示例不能被执行。这是用于代码片段,这些代码片段是用于读者的使用示例,并不是实际的测试用例。将编码参数添加到
testfile()
函数和DocFileSuite
类中以指定文件的编码。这使得在docstring中包含的测试中更容易使用非ASCII字符。(由Bjorn Tillenius提供)email
包已更新到4.0版。(由Barry Warsaw提供)fileinput
模块更灵活。Unicode filenames are now supported, and a mode parameter that defaults to"r"
was added to theinput()
function to allow opening files in binary or universal newlines mode. 另一个新参数openhook允许您使用除open()
之外的函数来打开输入文件。一旦迭代文件集,FileInput
对象的新fileno()
将返回当前打开文件的描述器。(由Georg Brandl提供)在
gc
模块中,新的get_count()
函数返回包含三个GC代的当前容器计数的三元组。这是垃圾收集器的记帐信息;当这些计数达到指定的阈值时,将进行垃圾容器扫描。现有的gc.collect()
函数现在接受可选的生成参数,即0,1或2,以指定要收集哪个生成。(由Barry Warsaw提供)heapq
模块中的nsmallest()
和nlargest()
函数现在支持一个key
关键字参数,类似于一个由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
。这使它与切片对象的属性更加兼容,因此您现在可以编写以下内容:s = slice(5) # Create slice object itertools.islice(iterable, s.start, s.stop, s.step)
(由Raymond Hettinger提供)
locale
模块中的format()
函数已修改,并添加了两个新函数,format_string()
和currency()
。只要不超过一个%char说明符出现,
format()
函数的val参数可以是一个字符串;现在参数必须正好是一个%char说明符,没有周围文本。还添加了可选的currency参数,如果True
,将使用区域设置的格式化货币的规则,在三位数的组之间放置分隔符。要格式化具有多个%char说明符的字符串,请使用
format()
的新format_string()
函数,但也支持将%char说明符与任意文本混合。还添加了一个新的
currency()
函数,根据当前语言环境的设置格式化一个数字。(由Georg Brandl提供)
mailbox
模块经历了大规模重写,以添加修改邮箱以及读取它们的功能。A new set of classes that includembox
,MH
, andMaildir
are used to read mailboxes, and have anadd(message)
method to add messages,remove(key)
to remove messages, andlock()
/unlock()
to lock/unlock the mailbox. 以下示例将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撰写。资金由Google的2005年夏季代码提供。)
新模块:
msilib
模块允许创建Microsoft Installer.msi
文件和CAB文件。还包括读取.msi
数据库的一些支持。(供稿:Martin vonLöwis。)The
nis
module now supports accessing domains other than the system default domain by supplying a domain argument to thenis.match()
andnis.maps()
functions. (由Ben Bell提供)operator
模块的itemgetter()
和attrgetter()
现在支持多个字段。A call such asoperator.attrgetter('a', 'b')
will return a function that retrieves thea
andb
attributes. 将此新功能与sort()
方法的key
参数结合使用,可以方便地使用多个字段对列表进行排序。(由Raymond Hettinger提供)optparse
模块已更新到Optik库的1.5.1版本。OptionParser
类获得了一个epilog
属性,一个将在帮助消息后打印的字符串和一个destroy()
由对象创建。(由Greg Ward提供)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()
。They’re similar thewaitpid()
function which waits for a child process to exit and returns a tuple of the process ID and its exit status, butwait3()
andwait4()
return additional information.wait3()
不接受进程ID作为输入,因此它等待任何子进程退出并返回一个3元组process-id,从resource.getrusage()
函数返回的退出状态 t>,资源使用wait4(pid)
会获取进程ID。(供稿:Chad J.施罗德。)在FreeBSD上,
os.stat()
函数现在返回具有纳秒分辨率的时间,返回的对象现在具有st_gen
和st_birthtime
。如果平台支持,则st_flags
属性也可用。(由Antti Louko和DiegoPettenò提供)pdb
模块提供的Python调试器现在可以存储在达到断点时执行的命令列表,并停止执行。Once breakpoint #1 has been created, entercommands 1
and enter a series of commands to be executed, finishing the list withend
. 命令列表可以包括恢复执行的命令,例如continue
或next
。(供稿人:GrégoireDooms。)pickle
和cPickle
模块不再接受来自__reduce__()
方法的返回值None
该方法必须返回一个元组的参数。返回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版本。(由Trent Mick提供)由
Queue
模块提供的Queue
类获得了两个新方法。join()
阻塞,直到队列中的所有项目都已检索,并且项目的所有处理工作都已完成。工作线程调用另一个新方法task_done()
,表示某个项目的处理已完成。(由Raymond Hettinger提供)旧的
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)
上的两种新方法将接收到的数据存储在支持缓冲区协议的对象中,而不是将数据作为串。这意味着您可以将数据直接放入数组或内存映射文件。Socket对象还获得了
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(缓冲区, 偏移量, v1, v2, ...)
和unpack_from(buffer, offset)方法。
这使您可以将数据直接存储到数组或内存映射文件中。(
Struct
对象由Bob Ippolito在NeedForSpeed冲刺中实现。对于缓冲区对象的支持由Martin Blais添加,也在NeedForSpeed sprint。)Python开发人员在2.5开发过程中从CVS切换到Subversion。有关精确构建版本的信息可以作为
sys.subversion
变量,一个三元组(interpreter-name, branch-name, / t4> revision-range)
。例如,在写我的2.5的副本报告('CPython', 'trunk', '45313:45315' / t3>
。此信息还可通过
Py_GetBuildInfo()
函数获得,该函数返回如下所示的构建信息字符串:“trunk:45355:45356M, Apr 13 2006, 07:42:19“
。(由Barry Warsaw提供)另一个新函数
sys._current_frames()
返回所有正在运行的线程的当前堆栈帧,作为将线程标识符映射到当前在该线程中被调用时的最顶层堆栈帧的字典。(由Tim Peters提供。)tarfile
模块中的TarFile
类现在具有一个extractall()
方法,将归档中的所有成员提取到当前工作目录中。还可以设置不同的目录作为提取目标,并且只分离存档成员的一个子集。现在可以使用模式
'r|*'
自动检测用于在流模式下打开的tarfile的压缩。(供稿人:LarsGustäbel。)threading
模块现在允许您设置创建新线程时使用的堆栈大小。stack_size([*size*])
函数返回当前配置的堆栈大小,并提供可选的size参数设置新值。不是所有的平台都支持更改堆栈大小,但是Windows,POSIX线程和OS / 2都支持。(由Andrew MacIntyre提供)unicodedata
模块已更新为使用版本4.1.0的Unicode字符数据库。某些规范需要版本3.2.0,因此它仍然可用作unicodedata.ucd_3_2_0
。新模块:
uuid
模块根据 RFC 4122生成通用唯一标识符(UUID)。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
模块的WeakKeyDictionary
和WeakValueDictionary
类型获得了迭代包含在字典中的弱引用的新方法。iterkeyrefs()
andkeyrefs()
methods were added toWeakKeyDictionary
, anditervaluerefs()
andvaluerefs()
were added toWeakValueDictionary
. (由Fred L. Drake,Jr.提供)webbrowser
模块接受了许多增强。现在可以使用python -m webbrowser
有多个开关来控制行为(对于新的浏览器窗口,-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
类以启用此功能。(供稿:Skip Montanaro。)zipfile
模块现在支持ZIP64版本的格式,这意味着.zip存档现在可以大于4 GiB,并且可以包含大于4 GiB的单个文件。(由Ronald Oussoren提供。)zlib
模块的Compress
和Decompress
对象现在支持一个copy()
方法,状态并返回新的Compress
或Decompress
对象。(由Chris AtLee提供)
The ctypes package¶
由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")
Type constructors for the various C types are provided: c_int()
, c_float()
, c_double()
, c_char_p()
(equivalent to char *
), and so forth. 与Python的类型不同,C版本都是可变的;您可以分配到它们的value
属性来更改包装的值。Python整数和字符串将自动转换为相应的C类型,但对于其他类型,必须调用正确的类型构造函数。(我的意思是必须;得到它错误通常会导致解释器崩溃与分段错误。)
当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
对象。This object does not release the global interpreter lock before calling a function, because the lock must be held when calling into the interpreter’s code. 有一个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中。
The ElementTree package¶
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) | 返回属性名称的值。 |
elem.set(name, value) | 为属性名称设置新值。 |
elem.attrib | 检索包含属性的字典。 |
del elem.attrib [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的值的字符,它将引发异常。因此,最好指定一个不同的编码,如UTF-8,可以处理任何Unicode字符。)
本节仅是对ElementTree接口的部分描述。有关详细信息,请阅读软件包的官方文档。
也可以看看
- http://effbot.org/zone/element-index.htm
- ElementTree的官方文档。
The hashlib package¶
添加了由Gregory P. Smith编写的新hashlib
模块以替换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()
返回具有相同摘要状态的新的哈希对象。
也可以看看
hashlib
模块的文档。
The sqlite3 package¶
用于SQLite嵌入式数据库的包装器的pysqlite模块(http://www.pysqlite.org)已经以包名称sqlite3
添加到标准库。
SQLite是一个C库,提供一个轻量级的基于磁盘的数据库,不需要单独的服务器进程,并允许使用非标准的SQL查询语言变体访问数据库。一些应用程序可以使用SQLite进行内部数据存储。还可以使用SQLite对应用程序进行原型化,然后将代码移植到更大的数据库(如PostgreSQL或Oracle)。
pysqlite由GerhardHä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编写。
The wsgiref package¶
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 Server网关接口v1.0
- PEP由Phillip J. Eby编写。
Build and C API Changes¶
对Python的构建过程和C API的更改包括:
Python源代码树在由Martin vonLöwis监督和完美执行的复杂迁移过程中从CVS转换为Subversion。程序开发为 PEP 347。
Coverity是一家销售源代码分析工具(Prevent)的公司,提供了他们对Python源代码的检查结果。分析发现了大约60个错误,迅速修复。许多错误都是重新计数问题,通常发生在错误处理代码中。有关统计信息,请参见https://scan.coverity.com。
C API的最大变化来自 PEP 353,它修改解释器使用
Py_ssize_t
类型定义而不是int
。有关此更改的讨论,请参见上一节PEP 353: Using ssize_t as the index type。字节码编译器的设计已经改变了很多,不再通过遍历解析树来生成字节码。相反,解析树被转换为抽象语法树(或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结构定义。ThePyParser_ASTFromString()
andPyParser_ASTFromFile()
, defined inInclude/pythonrun.h
, take Python source as input and return the root of an AST representing the contents. 然后可以通过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,在会议上的一些AST冲刺,如PyCon。
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,这些家庭现在做不同的事情,不匹配可能会导致segfault。你应该仔细测试你的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(type)
执行相同的操作,并请求函数内联。如果在python.h
之前定义PY_LOCAL_AGGRESSIVE()
,则为模块启用一组更积极的优化;您应该对结果进行基准化,以确定这些优化是否使代码更快。(由Fredrik Lundh在NeedForSpeed冲刺中提供。)PyErr_NewException(name, base, dict)
can now accept a tuple of base classes as its base argument. (由Georg Brandl提供)用于发出警告的
PyErr_Warn()
函数现已废弃,支持PyErr_WarnEx(category, message, stacklevel) / t5>
,可以指定分隔此函数和调用者的堆栈帧数。的堆栈水平是调用PyErr_WarnEx()
的函数,2是上面的函数,等等。(由Neal Norwitz补充。)CPython解释器仍然用C编写,但现在可以使用C ++编译器编译代码,而不会出错。(由Anthony Baxter,Martin vonLöwis,Skip Montanaro执行。)
PyRange_New()
函数已删除。它从来没有记录,从来没有在核心代码中使用,并有危险的错误检查。在不太可能的情况下,您的扩展程序正在使用它,您可以替换为类似如下:range = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll", start, stop, step);
Porting to Python 2.5¶
本部分列出了可能需要更改代码的上述更改:
- ASCII现在是模块的默认编码。如果模块包含具有8位字符的字符串面值,但没有编码声明,则现在是语法错误。在Python 2.4中,触发了警告,而不是语法错误。
- 以前,生成器的
gi_frame
属性总是一个框架对象。由于PEP 342: New Generator Features中描述的 PEP 342改变,现在可以gi_frame
为None
。 - 当您尝试比较Unicode字符串和不能使用默认ASCII编码转换为Unicode的8位字符串时,会触发新的警告
UnicodeWarning
。以前这种比较会引发UnicodeDecodeError
异常。 - 库:
csv
模块现在更严格的多行引用字段。如果文件包含嵌入字段中的换行符,则输入应按保留换行符的方式拆分成行。 - 库:只要不超过一个%char说明符出现,
locale
模块的format()
函数就会接受任何字符串。在Python 2.5中,参数必须恰好是一个没有周围文本的char 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: Using ssize_t as the index type。 - C API:obmalloc更改意味着您必须小心不要混合使用
PyMem_*()
和PyObject_*()
函数族。分配有一个族的*_Malloc()
的内存必须与相应系列的*_Free()
函数释放。
Acknowledgements¶
作者感谢以下人员为本文的各种草案提供建议,更正和协助:Georg Brandl,Nick Coghlan,Phillip J. Eby,LarsGustäbel,Raymond Hettinger,Ralf W. Grosse-Kunstleve,Kent Johnson, Iain Lowe,Martin vonLöwis,Fredrik Lundh,Andrew McNamara,Skip Montanaro,Gustavo Niemeyer,Paul Prescod,James Pryor,Mike Rovner,Scott Weikart,Barry Warsaw,Thomas Wouters。