python 2.0的新功能¶
- 作者
A.M.Kuchling和Moshe Zadka
介绍¶
2000年10月16日发布了一个新版本的python,版本2.0。本文介绍了2.0中令人兴奋的新特性,重点介绍了一些其他有用的更改,并指出了一些不兼容的更改,这些更改可能需要重写代码。
python的开发从来没有在发布之间完全停止过,并且始终提交稳定的bug修复和改进流。许多小的修正、一些优化、附加的docstring和更好的错误消息都进入了2.0;列出它们都是不可能的,但它们确实很重要。如果您想查看完整的列表,请查阅公开的CVS日志。这一进展是由于为pythonlabs工作的五个开发人员花了一天的时间来修复bug而获得报酬的,同时也是由于迁移到sourceforge后改进了通信。
python 1.6怎么样?¶
python 1.6可以看作是python发布的合同义务。在核心开发团队于2000年5月离开CNRI之后,CNRI要求创建一个1.6版本,包含在CNRI执行的所有关于Python的工作。因此,python 1.6代表了从2000年5月开始的cvs树的状态,最重要的新特性是unicode支持。当然,开发在5月之后继续,因此1.6树收到了一些修复,以确保它与Python2.0向前兼容。因此,1.6是Python进化的一部分,而不是分支。
那么,您应该对python 1.6感兴趣吗?大概不会。1.6最终版本和2.0beta1版本是在同一天(2000年9月5日)发布的,计划在大约一个月内完成python 2.0。如果你有需要维护的应用程序,那么通过移动到1.6,修复它们,然后在一个月内移动到2.0,再进行一轮破坏似乎没有什么意义;你最好直接转到2.0。本文档中描述的大多数真正有趣的功能都只在2.0中,因为在5月到9月之间做了很多工作。
新开发过程¶
python 2.0中最重要的变化可能根本不是代码,而是如何开发python:2000年5月,python开发人员开始使用sourceforge提供的工具来存储源代码、跟踪bug报告和管理补丁提交队列。要为python 2.0报告错误或提交修补程序,请使用python的项目页面(位于https://sourceforge.net/project s/python/)提供的错误跟踪和修补程序管理器工具。
现在托管在sourceforge的最重要的服务是python cvs树,它是一个版本控制的存储库,包含python的源代码。以前,大约有7个人可以写入cvs树,所有补丁都必须由这个短列表中的一个人检查和签入。显然,这不是非常可扩展的。通过将cvs树移到sourceforge,可以向更多人授予写访问权限;截至2000年9月,有27人能够签入更改,增加了四倍。这使得大规模的更改成为可能,如果需要通过一小群核心开发人员进行筛选,就不会尝试进行这种更改。例如,有一天,Peter Schneider Kamp突然想到放弃K&R C兼容性,将Python的C源代码转换为ANSI C。在获得了python dev邮件列表的批准后,他启动了一系列的签入,持续了大约一周,其他开发人员也加入了帮助,工作完成了。如果只有5个人具有写访问权限,那么该任务可能会被视为“不错,但不值得花费所需的时间和精力”,而且永远也不会完成。
使用SourceForge服务的转变导致了开发速度的显著提高。补丁现在被提交、评论、由原始提交者以外的人修改,并且在人们之间来回弹回,直到补丁被认为值得检查为止。Bug在一个中心位置被跟踪,并可以分配给特定的人进行修复,我们可以计算打开的Bug数量来衡量进度。这并非没有代价:开发人员现在有更多的电子邮件要处理,有更多的邮件列表要遵循,并且必须为新环境编写特殊的工具。例如,sourceforge发送了默认的补丁和错误通知电子邮件,这些邮件是完全无用的,所以ka-ping-yee编写了一个HTML屏幕抓取程序,可以发送更有用的消息。
添加代码的简单性导致了一些最初的增长难题,例如代码在准备好之前就签入了,或者没有得到开发人员组的明确同意。出现的审批流程与Apache Group使用的流程有些相似。开发人员可以在一个补丁上投票+1、+0、-0或-1;+1和-1表示接受或拒绝,而+0和-0意味着开发人员对更改基本上是漠不关心的,尽管有轻微的正或负倾斜。与阿帕奇模式相比,最显著的变化是投票本质上是咨询性的,让拥有仁慈独裁者身份的吉多·范·罗森知道一般的意见是什么。他仍然可以忽略投票结果,即使社区不同意他,他也可以批准或拒绝变更。
生成一个实际的补丁是添加新特性的最后一步,与之前提出一个好的设计的任务相比,通常很容易。对新特性的讨论常常会爆发成冗长的邮件列表线程,这使得讨论很难进行,而且没有人能够阅读到每个发布到python-dev的文章。因此,已经建立了一个相对正式的过程来编写python增强建议(peps),该过程是以Internet RFC过程为模型的。PEP是描述一个提议的新特征的文件草稿,并且不断地修改,直到社区达成共识,或者接受或者拒绝这个提议。引自引言 PEP 1 “PEP的目的和指导方针”:
PEP代表python增强方案。PEP是一个向Python社区提供信息或描述Python新特性的设计文档。PEP应提供功能的简明技术规范和功能的基本原理。
我们希望PEPS是提出新特性、收集社区对某个问题的输入以及记录进入Python的设计决策的主要机制。PEP负责在社区内建立共识,并记录不同意见。
阅读 PEP 1 有关PEP编辑流程、风格和格式的详细信息。PEP保存在sourceforge上的python cvs树中,尽管它们不是python 2.0发行版的一部分,也可以从https://www.python.org/dev/peps/以HTML格式提供。截至2000年9月,有25个PEP,范围从 PEP 201 “lockstep迭代”,到PEP 225,“elementwise/objectwise运算符”。
unicode¶
python 2.0中最大的新特性是一种新的基本数据类型:unicode字符串。Unicode使用16位数字来表示字符,而不是ASCII使用的8位数字,这意味着可以支持65536个不同的字符。
Unicode支持的最后一个接口是通过在python dev邮件列表上进行无数次经常充满风暴的讨论得到的,主要由Marc Andr_Lemburg基于Fredrik Lundh的Unicode字符串类型实现来实现。接口的详细解释被写成 PEP 100 “python unicode集成”。本文将简单介绍有关Unicode接口的最重要的几点。
在python源代码中,unicode字符串编写为 u"string"
. 可以使用新的转义序列写入任意Unicode字符, \uHHHH
在哪里 HHHH 是从0000到ffff的4位十六进制数。现有的 \xHHHH
也可以使用转义序列,对于u+01ff以下的字符可以使用八进制转义,其表示为 \777
.
Unicode字符串和普通字符串一样,是不可变的序列类型。它们可以被索引和切片,但不能就地修改。Unicode字符串具有 encode( [encoding] )
方法,返回所需编码中的8位字符串。编码是由字符串命名的,例如 'ascii'
, 'utf-8'
, 'iso-8859-1'
或者别的什么。编解码器API是为实现和注册新的编码而定义的,这些编码随后可在整个Python程序中使用。如果未指定编码,则默认编码通常为7位ASCII,但可以通过调用 sys.setdefaultencoding(encoding)
自定义版本中的函数 site.py
.
使用默认的ASCII编码,组合8位和Unicode字符串始终强制为Unicode;结果 'a' + u'bc'
是 u'abc'
.
已添加新的内置函数,并修改现有的内置函数以支持Unicode:
unichr(ch)
返回一个长度为1个字符的Unicode字符串,其中包含 ch .ord(u)
在哪里 u 是1个字符的正则字符串或Unicode字符串,以整数形式返回字符数。unicode(string [, encoding] [, errors] )
从8位字符串创建Unicode字符串。encoding
是一个命名要使用的编码的字符串。这个errors
参数指定对当前编码无效的字符的处理方式;传递'strict'
因为该值导致在任何编码错误上引发异常,而'ignore'
导致错误被静默忽略,并且'replace'
如果有任何问题,请使用u+fffd(官方替换字符)。这个
exec
语句,以及各种内置的eval()
,getattr()
和setattr()
也将接受Unicode字符串和常规字符串。(修复此问题的过程可能遗漏了一些内置函数;如果您发现一个接受字符串但根本不接受Unicode字符串的内置函数,请将其报告为bug。)
一个新的模块, unicodedata
提供到Unicode字符属性的接口。例如, unicodedata.category(u'A')
返回2个字符的字符串“l u”,表示它是字母的“l”,表示它是大写的“u”。 unicodedata.bidirectional(u'\u0660')
返回“an”,表示U+0660是阿拉伯数字。
这个 codecs
模块包含查找现有编码和注册新编码的函数。除非您想要实现一个新的编码,否则您将经常使用 codecs.lookup(encoding)
函数,返回4元素元组: (encode_func, decode_func, stream_reader, stream_writer)
.
encode_func 是一个接受Unicode字符串并返回2元组的函数
(string, length)
. string 是一个8位字符串,包含转换为给定编码的Unicode字符串的一部分(可能全部),以及 长度 告诉您Unicode字符串转换了多少。decode_func 与…相反 encode_func ,获取8位字符串并返回2元组
(ustring, length)
,由生成的Unicode字符串组成 护城河 整数 长度 说明8位字符串的消耗量。stream_reader 是支持从流解码输入的类。 stream_reader(file_obj) 返回一个支持
read()
,readline()
和readlines()
方法。这些方法都将从给定的编码转换并返回Unicode字符串。stream_writer 类似地,是支持对流进行编码输出的类。 stream_writer(file_obj) 返回一个支持
write()
和writelines()
方法。这些方法需要Unicode字符串,在输出时将其转换为给定的编码。
例如,以下代码将一个Unicode字符串写入一个文件,并将其编码为UTF-8::
import codecs
unistr = u'\u0660\u2000ab ...'
(UTF8_encode, UTF8_decode,
UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8')
output = UTF8_streamwriter( open( '/tmp/output', 'wb') )
output.write( unistr )
output.close()
然后,以下代码将从文件中读取UTF-8输入:
input = UTF8_streamreader( open( '/tmp/output', 'rb') )
print repr(input.read())
input.close()
支持Unicode的正则表达式可通过 re
模块,它有一个新的底层实现,称为SRE,由秘密实验室AB的Fredrik Lundh编写。
A -U
添加了命令行选项,使Python编译器将所有字符串文本解释为Unicode字符串文本。这是为了在测试和将来验证您的python代码时使用,因为将来的一些版本的python可能会放弃对8位字符串的支持,而只提供unicode字符串。
列表推导¶
列表是Python中的Workhorse数据类型,许多程序在某个时刻操纵列表。列表上的两个常见操作是循环它们,要么选择满足某个标准的元素,要么对每个元素应用一些函数。例如,给定一个字符串列表,您可能希望拉出包含给定子字符串的所有字符串,或者从每行中去掉尾随空格。
现有的 map()
和 filter()
函数可以用于此目的,但它们需要一个函数作为其参数之一。如果有一个现有的内置函数可以直接传递,这很好,但是如果没有,则必须创建一个小函数来完成所需的工作,而python的作用域规则会使结果变得丑陋,如果这个小函数需要额外的信息。以上一段中的第一个示例为例,查找包含给定子字符串的列表中的所有字符串。您可以编写以下内容:
# Given the list L, make a list of all strings
# containing the substring S.
sublist = filter( lambda s, substring=S:
string.find(s, substring) != -1,
L)
由于python的作用域规则,将使用默认参数,以便 lambda
表达式知道正在搜索什么子字符串。列表理解使此更清晰:
sublist = [ s for s in L if string.find(s, S) != -1 ]
列表理解的形式为:
[ expression for expr in sequence1
for expr2 in sequence2 ...
for exprN in sequenceN
if condition ]
这个 for
…… in
子句包含要迭代的序列。序列不一定是相同的长度,因为它们是 not 并行迭代,但从左到右;这在下面的段落中解释得更清楚。生成的列表的元素将是 表达 . 决赛 if
子句是可选的;如果存在, 表达 只有当 条件 是真的。
为了使语义非常清楚,列表理解相当于下面的Python代码:
for expr1 in sequence1:
for expr2 in sequence2:
...
for exprN in sequenceN:
if (condition):
# Append the value of
# the expression to the
# resulting list.
这意味着当存在多个 for
…… in
从句,得到的列表将等于所有序列长度的乘积。如果有两个长度为3的列表,则输出列表的长度为9个元素:
seq1 = 'abc'
seq2 = (1,2,3)
>>> [ (x,y) for x in seq1 for y in seq2]
[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1),
('c', 2), ('c', 3)]
为了避免在Python语法中引入歧义,如果 表达 正在创建元组,它必须用括号括起来。下面的第一个列表理解是语法错误,而第二个是正确的:
# Syntax error
[ x,y for x in seq1 for y in seq2]
# Correct
[ (x,y) for x in seq1 for y in seq2]
列表理解的概念最初来自函数式编程语言haskell(https://www.haskell.org)。Greg Ewing认为将它们添加到python中最有效,并编写了最初的列表理解补丁,然后在python dev邮件列表上讨论了似乎无穷无尽的时间,并由skip montanaro保持最新。
增广的任务¶
另一个长期被要求的特性,增强的赋值操作符,已经被添加到python 2.0中。增强的赋值运算符包括 +=
, -=
, *=
等等。例如,语句 a += 2
增加变量的值 a
乘以2,相当于稍长的 a = a + 2
.
支持的分配运算符的完整列表为 +=
, -=
, *=
, /=
, %=
, **=
, &=
, |=
, ^=
, >>=
和 <<=
. python类可以通过定义名为 __iadd__()
, __isub__()
等。例如,以下内容 Number
类存储一个数字,并支持使用+=创建具有递增值的新实例。
class Number:
def __init__(self, value):
self.value = value
def __iadd__(self, increment):
return Number( self.value + increment)
n = Number(5)
n += 3
print n.value
这个 __iadd__()
使用增量值调用特殊方法,并应返回具有适当修改值的新实例;此返回值被绑定为左侧变量的新值。
增广的赋值运算符最初是在C编程语言中引入的,大多数C派生语言,如 awk ,C++、Java、Perl和PHP也支持它们。增强分配补丁由Thomas Wouters实现。
字符串方法¶
到目前为止,字符串操作功能在 string
模块,通常是 strop
用C编写的模块。添加Unicode对 strop
模块,因为函数都需要重写才能接受8位或Unicode字符串。用于以下功能: string.replace()
它接受3个字符串参数,这意味着8个可能的排列,以及相应复杂的代码。
相反,python 2.0把问题推到了字符串类型上,通过8位字符串和unicode字符串上的方法实现了字符串操作功能。地址:
>>> 'andrew'.capitalize()
'Andrew'
>>> 'hostname'.replace('os', 'linux')
'hlinuxtname'
>>> 'moshe'.find('sh')
2
有一件事没有改变,一个值得注意的愚人节玩笑,尽管如此,那就是python字符串是不变的。因此,string方法返回新的字符串,并且不修改它们所操作的字符串。
老年人 string
模块仍然具有向后兼容性,但它主要充当新字符串方法的前端。
在2.0之前的版本中没有并行的两种方法,尽管它们在jpython中存在了相当长的一段时间,但是它们是 startswith()
和 endswith()
. s.startswith(t)
等于 s[:len(t)] == t
,同时 s.endswith(t)
等于 s[-len(t):] == t
.
另一个值得特别提及的方法是 join()
. 这个 join()
字符串的方法接收一个参数、字符串序列,并等效于 string.join()
旧款功能 string
模块,参数颠倒。换言之, s.join(seq)
相当于旧的 string.join(seq, s)
.
循环垃圾收集¶
python的C实现使用引用计数来实现垃圾收集。每个python对象都维护指向自身的引用数量的计数,并在创建或销毁引用时调整计数。一旦引用计数达到零,对象就不再可访问,因为您需要有一个对对象的引用来访问它,并且如果该计数为零,则不再存在引用。
引用计数具有一些令人愉快的特性:它易于理解和实现,并且所得到的实现是可移植的,速度相当快,并且与实现自己的内存处理方案的其他库反应良好。引用计数的主要问题是,它有时没有意识到对象不再可访问,从而导致内存泄漏。当存在引用循环时,就会发生这种情况。
考虑最简单的可能循环,一个引用自身的类实例:
instance = SomeClass()
instance.myself = instance
执行上述两行代码后,参考计数为 instance
是2;一个引用来自名为 'instance'
另一个来自 myself
实例的属性。
如果下一行代码是 del instance
,发生了什么?的引用计数 instance
减少1,因此其引用计数为1;中的引用 myself
属性仍然存在。然而,该实例不再可以通过Python代码访问,它可以被删除。如果多个对象彼此具有引用,则它们可以参与一个循环,从而导致所有对象泄漏。
python 2.0通过定期执行循环检测算法来解决这个问题,该算法查找不可访问的循环并删除相关的对象。一个新的 gc
模块提供执行垃圾收集、获取调试统计信息和调整收集器参数的功能。
运行周期检测算法需要一些时间,因此会导致一些额外的开销。希望在我们从使用2.0中获得使用周期集合的经验之后,python 2.1能够通过仔细的调优将开销最小化。目前还不清楚会损失多少性能,因为基准测试很复杂,而且关键取决于程序创建和销毁对象的频率。在编译python时,如果您甚至不能承受很小的速度损失,或者通过指定 --without-cycle-gc
运行时切换 configure 脚本。
有几个人解决了这个问题,并为解决这个问题作出了贡献。Toby Kelsey编写了周期检测方法的早期实现。Eric Tiedemann在访问CNRI时提出了当前的算法,Guido van Rossum和Neil Schemenauer编写了两个不同的实现,之后由Neil集成。在这一过程中,很多人都提出了建议;2000年3月的python dev邮件列表档案包含了大部分相关的讨论,特别是在标题为“为python收集参考周期”和“再次完成”的线程中。
其他核心变更¶
对python的语法和内置函数进行了各种细微的更改。这些变化都不是很深远,但它们是方便的。
次要语言更改¶
新的语法使用参数元组和/或关键字参数字典调用给定函数更加方便。在python 1.5及更早版本中,您将使用 apply()
内置功能: apply(f, args, kw)
调用函数 f()
用参数tuple args 以及字典中的关键字参数 kw . apply()
在2.0中是一样的,但是多亏了Greg Ewing的一个补丁, f(*args, **kw)
是一种更短更清晰的方法来达到同样的效果。此语法与定义函数的语法对称:
def f(*args, **kw):
# args is a tuple of positional args,
# kw is a dictionary of keyword args
...
这个 print
语句的输出现在可以指向类似文件的对象,方法是 print
具有 >> file
类似于Unix shell中的重定向操作符。以前你要么用 write()
类文件对象的方法,缺乏 print
,或者可以将新值赋给 sys.stdout
然后恢复旧值。对于将输出发送到标准错误,更容易编写:
print >> sys.stderr, "Warning: action field not supplied"
模块现在可以在导入时使用语法重命名。 import module as name
或 from module import name as othername
. 补丁是由托马斯·沃特斯提交的。
当使用 %
运算符;“%r”将插入 repr()
它的参数。这也是从对称性考虑中添加的,这次是为了与现有的格式样式“%s”对称,该格式样式插入了 str()
它的参数。例如, '%r %s' % ('abc', 'abc')
返回一个包含 'abc' abc
.
以前没有办法实现一个超越Python内置的类 in
并实现了一个自定义版本。 obj in seq
返回true obj 出现在序列中 seq ;python只需尝试序列的每个索引,直到 obj 被发现或被发现 IndexError
遇到。Moshe Zadka贡献了一个补丁,增加了 __contains__()
为提供自定义实现的魔力方法 in
.此外,用C编写的新内置对象可以定义 in
指通过序列协议中的新插槽为它们提供。
早期版本的python使用递归算法删除对象。深度嵌套的数据结构可能导致解释器填满C堆栈并崩溃;Christian Tismer重写了删除逻辑来解决这个问题。在相关的注释中,比较递归对象无限地循环并崩溃;JeremyHylton重写了代码以不再崩溃,从而产生了一个有用的结果。例如,在该代码之后:
a = []
b = []
a.append(a)
b.append(b)
比较 a==b
返回true,因为这两个递归数据结构是同构的。请参阅python dev邮件列表的2000年4月存档中的线程“垃圾桶和pr_7”,以了解此实现之前的讨论,以及一些有用的相关链接。请注意,比较现在也可以引发异常。在早期版本的python中,比较操作,如 cmp(a,b)
即使是用户定义的 __cmp__()
方法遇到错误,因为生成的异常将被静默接受。
在将python移植到Itanium处理器上的64位窗口上已经做了很多工作,主要是由ActiveState的TrentMick完成的。(令人困惑地, sys.platform
仍然是 'win32'
在WIN64上,因为为了便于移植,MS VisualC++将代码视为ItAuthic上的32位。PythOnWin还支持Windows CE;请查看HTTP://PythOn.SooSurfGe.NET/Python CE页面以获取更多信息。
另一个新平台是darwin/macos x;对它的最初支持是在python 2.0中。如果指定“configure--with dyld--with suffix=.x”,动态加载就可以工作。有关更多说明,请参阅python源代码发行版中的自述文件。
人们试图减轻 Python 的一个疣,这种疣经常让人困惑。 NameError
在为变量赋值之前,代码引用局部变量时出现异常。例如,以下代码在 print
1.5.2和2.0中的声明;1.5.2 a中的声明 NameError
引发异常,而2.0引发新的 UnboundLocalError
例外。 UnboundLocalError
是的子类 NameError
,所以需要 NameError
待抚养的子项仍然可以工作。地址:
def f():
print "i=",i
i = i + 1
f()
两个新的例外, TabError
和 IndentationError
,已经介绍。它们都是 SyntaxError
,并在发现Python代码缩进不正确时引发。
对内置函数的更改¶
一个新的内置的, zip(seq1, seq2, ...)
,已添加。 zip()
返回一个元组列表,其中每个元组包含每个参数序列中的第i个元素。两者之间的区别 zip()
和 map(None, seq1, seq2)
那是 map()
在序列中添加 None
如果序列的长度不一致, zip()
将返回的列表截断为最短参数序列的长度。
这个 int()
和 long()
当第一个参数是字符串时,函数现在接受一个可选的“base”参数。 int('123', 10)
返回123,而 int('123', 16)
返回291。 int(123, 16)
提高 TypeError
消息“can't convert non string with explicit base”出现异常。
一个包含更详细版本信息的新变量已添加到 sys
模块。 sys.version_info
是元组 (major, minor, micro, level, serial)
例如,在假设的2.0.1节1中, sys.version_info
将是 (2, 0, 1, 'beta', 1)
. level 是一个字符串,例如 "alpha"
, "beta"
或 "final"
最终版本。
字典有一种奇怪的新方法, setdefault(key, default)
,其行为类似于现有的 get()
方法。但是,如果钥匙丢失, setdefault()
两者都返回 default 作为 get()
可以,并将其作为的值插入字典 key . 因此,以下代码行:
if dict.has_key( key ): return dict[key]
else:
dict[key] = []
return dict[key]
可以简化为单个 return dict.setdefault(key, [])
语句。
解释器设置最大递归深度,以便在填充C堆栈并导致核心转储或GPF之前捕获失控的递归。以前在编译python时这个限制是固定的,但是在2.0中,可以使用 sys.getrecursionlimit()
和 sys.setrecursionlimit()
. 默认值为1000,通过运行新脚本可以找到给定平台的大致最大值, Misc/find_recursionlimit.py
.
移植到2.0¶
新的python版本试图与以前的版本兼容,而且记录非常好。然而,一些变更被认为是足够有用的,通常是因为它们修复了最初的设计决策,结果发现这些决策是主动错误的,破坏向后兼容性并不总是可以避免的。本节列出了python 2.0中可能导致旧python代码中断的更改。
可能会破坏大多数代码的更改是收紧某些方法接受的参数。有些方法会采用多个参数,并将它们视为一个元组,特别是各种列表方法,例如 append()
和 insert()
. 在早期版本的python中,如果 L
是一个列表, L.append( 1,2 )
附加元组 (1,2)
到列表中。在python 2.0中,这会导致 TypeError
将引发异常,并显示消息:“append正好需要1个参数;已给定2个”。解决方法是简单地添加一组额外的圆括号,将两个值作为元组传递: L.append( (1,2) )
.
这些方法的早期版本更容易理解,因为它们在Python的C接口中使用了一个旧函数来解析它们的参数;2.0使它们更现代化以使用 PyArg_ParseTuple()
当前参数解析函数,它提供更多有用的错误消息,并将多参数调用视为错误。如果必须使用2.0但无法修复代码,则可以编辑 Objects/listobject.c
并定义预处理器符号 NO_STRICT_LIST_APPEND
为了保持旧的行为,不建议这样做。
中的一些函数 socket
模块仍然可以这样原谅。例如, socket.connect( ('hostname', 25) )()
是正确的形式,传递表示IP地址的元组,但是 socket.connect( 'hostname', 25 )()
同样有效。 socket.connect_ex()
和 socket.bind()
同样容易相处。2.0alpha1加强了这些功能,但由于文档实际上使用了错误的多参数形式,许多人编写了代码,这将打破更严格的检查。在面对公众的反应时,全球汽车规则拒绝了这些变化,因此 socket
模块,文档已修复,多参数窗体仅标记为已弃用;它 will 在将来的python版本中再次收紧。
这个 \x
字符串文本中的转义现在只需要2个十六进制数字。以前,它会使用“x”后面的所有十六进制数字,并获取结果的最低8位,所以 \x123456
相当于 \x56
.
这个 AttributeError
和 NameError
异常有一个更友好的错误消息,其文本如下 'Spam' instance has no attribute 'eggs'
或 name 'eggs' is not defined
. 以前,错误消息只是缺少的属性名 eggs
和利用这一事实编写的代码将在2.0中中断。
一些工作已经完成,使整数和长整数更可互换一点。在1.5.2中,为Solaris添加了大型文件支持,以允许读取大于2 GiB的文件;这使得 tell()
文件对象的方法返回一个长整数,而不是常规整数。有些代码会减去两个文件偏移量,并尝试使用结果来乘一个序列或切片一个字符串,但这会引发 TypeError
. 在2.0中,长整数可以用来对一个序列进行乘法或切片,并且它的行为将如您直观地期望的那样; 3L * 'abc'
生成“abcabcabc”,并且 (0,1,2,3)[2L:4L]
生产(2,3)。长整数也可以在以前只接受整数的各种上下文中使用,例如 seek()
文件对象的方法,以及 %
操作人员 (%d
, %i
, %x
等)。例如, "%d" % 2L**64
将生成字符串 18446744073709551616
.
最细微的长整数变化是 str()
但是,长整数的后面不再有“l”字符 repr()
还包括它。“l”这个词让许多想打印长整数的人很恼火,因为长整数看起来就像普通整数,因为他们必须用自己的方式去切掉字符。这不再是2.0中的问题,而是可以解决问题的代码 str(longval)[:-1]
假设“L”在这里,现在将丢失最后一个数字。
采取 repr()
浮点数的格式精度与 str()
. repr()
使用 %.17g
C的格式字符串 sprintf()
,同时 str()
使用 %.12g
像以前一样。结果是 repr()
有时显示的小数位数可能比 str()
,对于某些数字。例如,数字8.1不能精确地用二进制表示,所以 repr(8.1)
是 '8.0999999999999996'
,而str(8.1)是 '8.1'
.
这个 -X
命令行选项已被删除,它将所有标准异常转换为字符串而不是类;标准异常现在总是类。这个 exceptions
包含标准异常的模块从python转换为内置的C模块,由BarryWarsaw和FredrikLundh编写。
扩展/嵌入更改¶
其中一些更改是隐藏的,只有编写C扩展模块或在更大的应用程序中嵌入一个Python解释器的人才能看到。如果您不处理Python的C API,可以安全地跳过这一部分。
python c api的版本号增加了,因此必须重新编译为1.5.2编译的C扩展才能使用2.0。在Windows上,由于Windows DLL的工作方式,python 2.0不可能导入为python 1.5.x构建的第三方扩展,因此python将引发异常,导入将失败。
Jim Fulton的extensionclass模块的用户会很高兴地发现,已经添加了钩子,因此extensionclass现在得到了 isinstance()
和 issubclass()
. 这意味着您不再需要记住编写诸如 if type(obj) == myExtensionClass
但可以使用更自然的 if isinstance(obj, myExtensionClass)
.
这个 Python/importdl.c
这个文件是大量的ifdef来支持在许多不同平台上的动态加载,由greg stein清理并重新组织。 importdl.c
现在相当小,平台特定的代码已经移动到 Python/dynload_*.c
文件夹。另一个清理:还有一些 my*.h
包含各种可移植性黑客的include/目录中的文件;它们已合并为单个文件, Include/pyport.h
.
Vladimir Marangozov期待已久的malloc重组已经完成,为了便于让python解释器使用自定义分配器而不是C的标准 malloc()
. 有关文档,请阅读 Include/pymem.h
和 Include/objimpl.h
. 关于界面开发过程中的冗长讨论,请参见python.org上“补丁”和“python dev”列表的Web档案。
用于MacOS的gusi开发环境的最新版本支持posix线程。因此,Python的POSIX线程支持现在可以在Macintosh上工作。使用用户空间GNU的线程支持 pth
类库也有贡献。
Windows上的线程支持也得到了增强。Windows支持仅在争用情况下才使用内核对象的线程锁;在没有争用的常见情况下,它们使用更简单的函数,速度快一个数量级。NT上的python 1.5.2线程版本的速度是无线程版本的两倍;随着2.0的变化,两者之间的差异仅为10%。这些改进是雅科夫·马尔科维奇的贡献。
python 2.0的源代码现在只使用ansi c c原型,所以编译python现在需要一个ansi c c编译器,而不能再使用只支持k&r c的编译器。
以前,python虚拟机在字节码中使用16位数字,限制了源文件的大小。特别是,这会影响python源代码中文字列表和字典的最大大小;偶尔生成python代码的人会遇到这种限制。查尔斯·G·瓦尔德曼的一个补丁把极限从 2^16
到 2^{{32}}
.
添加了三个新的方便函数,用于在模块初始化时向模块字典中添加常量: PyModule_AddObject()
, PyModule_AddIntConstant()
和 PyModule_AddStringConstant()
. 这些函数中的每一个都接受一个模块对象、一个以空结尾的包含要添加的名称的C字符串,以及要分配给该名称的值的第三个参数。第三个参数分别是python对象、c long或c字符串。
为UNIX样式的信号处理程序添加了封装API。 PyOS_getsig()
获取信号处理程序并 PyOS_setsig()
将设置新的处理程序。
distutils:使模块易于安装¶
在python 2.0之前,安装模块是一件乏味的事情——没有办法自动确定在哪里安装了python,或者为扩展模块使用什么编译器选项。软件作者必须经历一个艰难的过程,即编辑makefile和配置文件,这些文件只在Unix上工作,不支持Windows和MacOS。python用户面临着各种各样的安装指令,这些指令在不同的扩展包之间有所不同,这使得管理python安装有些麻烦。
由GregWard领导的用于分发实用程序的SIG创建了distutils,一个使包安装更加容易的系统。它们构成了 distutils
包,是Python标准库的一个新部分。在最好的情况下,从源代码安装一个python模块需要相同的步骤:首先,您的意思只是解包tarball或zip归档文件,然后运行“python setup.py install`”。将自动检测平台,识别编译器,编译C扩展模块,并将分发安装到正确的目录中。可选的命令行参数提供了对安装过程的更多控制,distutils包提供了许多替代默认值的地方——将构建与安装分离,在非默认目录中构建或安装,等等。
为了使用distutils,需要编写一个 setup.py
脚本。对于简单的情况,当软件仅包含.py文件时,最小 setup.py
可能只有几行长:
from distutils.core import setup
setup (name = "foo", version = "1.0",
py_modules = ["module1", "module2"])
这个 setup.py
如果软件包含以下几个包,那么文件就不复杂了:
from distutils.core import setup
setup (name = "foo", version = "1.0",
packages = ["package", "package.subpackage"])
C扩展可能是最复杂的情况;下面是PYXML包中的一个示例:
from distutils.core import setup, Extension
expat_extension = Extension('xml.parsers.pyexpat',
define_macros = [('XML_NS', None)],
include_dirs = [ 'extensions/expat/xmltok',
'extensions/expat/xmlparse' ],
sources = [ 'extensions/pyexpat.c',
'extensions/expat/xmltok/xmltok.c',
'extensions/expat/xmltok/xmlrole.c', ]
)
setup (name = "PyXML", version = "0.5.4",
ext_modules =[ expat_extension ] )
distuils还可以负责创建源分布和二进制分布。由“python setup.py sdist````运行的“sdist”命令构建一个源分发,例如 foo-1.0.tar.gz
. 添加新命令并不困难,“bdist_RPM”和“bdist_Wininst”命令已经被用于分别为软件创建一个RPM分发和一个Windows安装程序。用于创建其他分发格式(如Debian包和Solaris)的命令 .pkg
文件处于不同的开发阶段。
所有这些都记录在新手册中, 分发python模块 ,它连接了基本的Python文档集。
XML模块¶
python 1.5.2以 xmllib
模块,由Sjoerd Mullender提供。自1.5.2发布以来,处理XML的两个不同接口已经变得很常见:SAX2(SimpleAPI for XML的版本2)提供了一个事件驱动接口,与 xmllib
和DOM(文档对象模型)提供了一个基于树的接口,将XML文档转换为一个可以遍历和修改的节点树。python 2.0包括一个sax2接口和一个剥离的dom接口,作为 xml
包裹。在这里,我们将简要概述这些新接口;有关完整的详细信息,请参阅Python文档或源代码。python XML SIG也在研究改进的文档。
SAX2支撑¶
SAX定义了用于解析XML的事件驱动接口。要使用SAX,必须编写SAX处理程序类。处理程序类继承自SAX提供的各种类,并重写XML解析器随后将调用的各种方法。例如, startElement()
和 endElement()
对解析器遇到的每个开始和结束标记调用方法, characters()
方法是为每个字符数据块调用的,等等。
事件驱动方法的优点是,整个文档在任何时候都不必驻留在内存中,这对于处理真正庞大的文档很重要。但是,如果您试图以某种详细的方式修改文档结构,那么编写SAX处理程序类可能会变得非常复杂。
例如,这个小示例程序定义了一个处理程序,它为每个开始和结束标记打印一条消息,然后解析该文件。 hamlet.xml
使用:
from xml import sax
class SimpleHandler(sax.ContentHandler):
def startElement(self, name, attrs):
print 'Start of element:', name, attrs.keys()
def endElement(self, name):
print 'End of element:', name
# Create a parser object
parser = sax.make_parser()
# Tell it what handler to use
handler = SimpleHandler()
parser.setContentHandler( handler )
# Parse a file!
parser.parse( 'hamlet.xml' )
有关详细信息,请参阅python文档,或http://pyxml.sourceforge.net/topics/howto/xml-howto.html上的xml howto。
DOM支持¶
文档对象模型是基于树的XML文档表示。顶层 Document
实例是树的根,它有一个子级,即顶层 Element
实例。这个 Element
具有表示字符数据和任何子元素的子节点,这些子元素可能有自己的子元素,等等。使用DOM,您可以随意遍历生成的树,访问元素和属性值,插入和删除节点,并将树转换回XML。
DOM对于修改XML文档很有用,因为您可以创建一个DOM树,通过添加新节点或重新排列子树来修改它,然后生成一个新的XML文档作为输出。您还可以手动构造一个DOM树并将其转换为XML,这是一种比简单地编写更灵活的生成XML输出的方法。 <tag1>
…… </tag1>
一个文件。
包含在python中的dom实现存在于 xml.dom.minidom
模块。它是级别1 DOM的轻量级实现,支持XML名称空间。这个 parse()
和 parseString()
提供了生成DOM树的方便函数:
from xml.dom import minidom
doc = minidom.parse('hamlet.xml')
doc
是一个 Document
实例。 Document
和所有其他的DOM类一样,例如 Element
和 Text
,是 Node
基类。因此,DOM树中的所有节点都支持某些常用方法,例如 toxml()
返回包含节点及其子节点的XML表示形式的字符串。每个类也有自己的特殊方法;例如, Element
和 Document
实例具有查找具有给定标记名的所有子元素的方法。从前面的两行示例继续:
perslist = doc.getElementsByTagName( 'PERSONA' )
print perslist[0].toxml()
print perslist[1].toxml()
对于 哈姆雷特 xml文件,上面几行输出:
<PERSONA>CLAUDIUS, king of Denmark. </PERSONA>
<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA>
文档的根元素可用为 doc.documentElement
可以通过删除、添加或删除节点来轻松修改其子级:
root = doc.documentElement
# Remove the first child
root.removeChild( root.childNodes[0] )
# Move the new first child to the end
root.appendChild( root.childNodes[0] )
# Insert the new first child (originally,
# the third child) before the 20th child.
root.insertBefore( root.childNodes[0], root.childNodes[20] )
同样,我将参考python文档以获得 Node
类及其各种方法。
与pyxml的关系¶
XML特殊兴趣小组已经研究了一段时间与XML相关的Python代码。其代码分发名为pyxml,可从sig的网页https://www.python.org/community/sig s/current/xml-sig获得。pyxml分发还使用包名称 xml
. 如果您已经编写了使用pyxml的程序,那么您可能会想知道它与2.0的兼容性。 xml
包裹。
答案是python 2.0的 xml
包与pyxml不兼容,但可以通过安装最新版本的pyxml使其兼容。许多应用程序都可以通过python 2.0中包含的XML支持,但更复杂的应用程序需要安装完整的pyxml包。安装后,pyxml版本0.6.0或更高版本将替换 xml
随python一起提供的包,将是一个严格的标准包的超集,添加了一系列附加功能。pyxml中的一些附加功能包括:
4DOM,来自Fourthought,Inc.的完整DOM实现。
xmlproc验证解析器,由lars marius garshol编写。
这个
sgmlop
解析器加速模块,由Fredrik Lundh编写。
模块变更¶
对python广泛的标准库进行了许多改进和错误修复;一些受影响的模块包括 readline
, ConfigParser
, cgi
, calendar
, posix
, readline
, xmllib
, aifc
, chunk, wave
, random
, shelve
和 nntplib
.请参阅cvs日志以了解补丁的详细信息。
Brian Gallew为 socket
模块。OpenSSL是安全套接字层的一种实现,它对通过套接字发送的数据进行加密。编译python时,可以编辑 Modules/Setup
要包括SSL支持,它将向 socket
模块: socket.ssl(socket, keyfile, certfile)
,它接受一个socket对象并返回一个ssl套接字。这个 httplib
和 urllib
模块也被更改为支持 https://
虽然没有人通过SSL实现ftp或smtp。
这个 httplib
Greg Stein重写了模块以支持HTTP/1.1。与1.5版本的 httplib
但是,如果使用HTTP/1.1特性(如管道),则需要重写代码才能使用不同的接口集。
这个 Tkinter
模块现在支持Tcl/Tk版本8.1、8.2或8.3,而对旧版本7.x的支持已经被放弃。tkinter模块现在支持在tk小部件中显示unicode字符串。此外,Fredrik Lundh还提供了一个优化方案,使得 create_line
和 create_polygon
更快,尤其是在使用大量坐标时。
这个 curses
模块得到了极大的扩展,从Oliver Andrich的增强版开始,提供了许多来自ncurses和sysv curses的附加功能,如颜色、可选字符集支持、pads和鼠标支持。这意味着模块不再与只有BSDcurses的操作系统兼容,但似乎没有任何当前维护的OSE属于此类。
正如前面讨论的2.0的Unicode支持中所提到的,由 re
模块已更改。SRE是一个新的正则表达式引擎,由Fredrik Lundh编写,部分由Hewlett-Packard资助,它支持对8位字符串和Unicode字符串进行匹配。
新模块¶
添加了许多新模块。我们将简单地列出它们的简要描述;有关特定模块的详细信息,请参阅2.0文档。
atexit
:用于注册要在Python解释器退出之前调用的函数。当前设置的代码sys.exitfunc
应直接更改为使用atexit
而不是模块,导入atexit
呼唤atexit.register()
在退出时调用函数。(由Skip Montanaro提供。)codecs
,encodings
,unicodedata
:作为新Unicode支持的一部分添加。filecmp
:取代旧的cmp
,cmpcache
和dircmp
模块,现在已弃用。(由戈登·麦克米伦和莫什·扎达卡提供。)gettext
:此模块通过向GNU GetText消息目录库提供接口,为python程序提供国际化(i18n)和本地化(l10n)支持。(由巴里·华沙(Barry Warsaw)整合,马丁·冯·卢维斯(Martin von L_wis)、彼得·芬克(Peter Funk)和詹姆斯·亨斯特里奇(James Henstridge)分别贡献。)linuxaudiodev
:支持/dev/audio
Linux上的设备,现有的一对sunaudiodev
模块。(由彼得·博什提供,杰里米·希尔顿提供修复。)mmap
:Windows和Unix上内存映射文件的接口。一个文件的内容可以直接映射到内存中,此时它的行为就像一个可变的字符串,所以它的内容可以被读取和修改。它们甚至可以传递给期望普通字符串的函数,例如re
模块。(萨姆·拉什的贡献,还有A.M.库奇林的一些扩展。)pyexpat
:expat XML解析器的接口。(由Paul Prescod提供。)robotparser
:分析Arobots.txt
文件,用于编写Web蜘蛛,礼貌地避开网站的某些区域。解析器接受robots.txt
文件,从中构建一组规则,然后可以回答有关给定URL可获取性的问题。(由Skip Montanaro提供。)tabnanny
:一个模块/脚本,用于检查python源代码是否存在不明确的缩进。(蒂姆·彼得斯供稿)UserString
:用于派生行为类似字符串的对象的基类。webbrowser
:提供独立于平台的方式在特定URL上启动Web浏览器的模块。对于每个平台,不同的浏览器按特定的顺序进行尝试。用户可以通过设置 BROWSER 环境变量。(最初的灵感来自埃里克·S·雷蒙德的补丁urllib
它增加了类似的功能,但最终的模块来自于最初由FredDrake实现的代码Tools/idle/BrowserControl.py
并改编为弗雷德的标准类库。)_winreg
:Windows注册表的接口。_winreg
是对自1995年以来作为pythonwin一部分的函数的一种改编,但现在已添加到核心发行版中,并增强以支持Unicode。_winreg
是比尔·塔特和马克·哈蒙德写的。zipfile
:用于读取和写入zip格式存档的模块。这些档案是由 PKZIP 在DOS/Windows或 zip 在Unix上,不要混淆 gzip -格式化文件(由gzip
模块(由James C.Ahlstrom贡献)imputil
:一个模块,与现有模块相比,它为编写自定义导入挂钩提供了一种更简单的方法。ihooks
模块。(由GregStein实现,沿途有很多关于python dev的讨论。)
闲置改进¶
idle是正式的python跨平台IDE,使用tkinter编写。python 2.0包括idle 0.6,这增加了一些新的特性和改进。部分列表:
用户界面的改进和优化,特别是在语法突出显示和自动缩进方面。
类浏览器现在显示更多信息,例如模块中的顶级函数。
选项卡宽度现在是用户可设置的选项。打开现有的python文件时,idle会自动检测缩进约定并进行调整。
现在支持在各种平台上调用浏览器,用于在浏览器中打开Python文档。
idle现在有一个命令行,这在很大程度上类似于普通的python解释器。
许多地方都增加了通话提示。
现在可以将idle作为包安装。
在编辑器窗口中,底部现在有一个行/列栏。
三个新的按键命令:检查模块 (Alt-F5 )导入模块 (F5 )运行脚本 (Ctrl-F5 )
已删除和已弃用的模块¶
一些模块被丢弃是因为它们已经过时了,或者因为现在有更好的方法来做同样的事情。这个 stdwin
模块已经不存在了;它是为一个不再开发的独立于平台的窗口工具包开发的。
一些模块已移动到 lib-old
子目录: cmp
, cmpcache
, dircmp
, dump
, find
, grep
, packmail
, poly
, util
, whatsound
, zmod
. 如果您的代码依赖于已移动到的模块 lib-old
,只需将该目录添加到 sys.path
为了让它们返回,但是我们鼓励您更新任何使用这些模块的代码。
确认¶
作者要感谢以下人士对本文的各种草稿提出建议:David Bolen、Mark Hammond、Gregg Hauser、Jeremy Hylton、Fredrik Lundh、Detlef Lannert、Aahz Maruch、Skip Montanaro、Vladimir Marangozov、Tobias Polzin、Guido van Rossum、Neil Schemenauer和Russ Schmidt。