python 2.4的新功能

作者

库克林

本文解释了2005年3月30日发布的python 2.4.1中的新特性。

Python2.4是一个中型版本。它引入的更改没有激进的python 2.2那么多,但引入的特性比保守的2.3版本要多。最重要的新语言特性是函数修饰符和生成器表达式;大多数其他更改是对标准库的更改。

根据cvs更改日志,在python 2.3和2.4之间应用了481个补丁,修复了502个bug。这两个数字都可能被低估。

本文并不试图提供每个新特性的完整规范,而是提供每个特性的简要介绍。有关完整的详细信息,您应该参考python 2.4的文档,例如python库参考和python参考手册。通常情况下,您会向PEP了解一个特定的新特性,以解释实现和设计原理。

PEP 218:内置集合对象

python 2.3引入了 sets 模块。C集合数据类型的实现现在作为两种新的内置类型添加到了Python核心中, set(iterable)frozenset(iterable) . 它们为成员资格测试、从序列中消除重复项以及联合、交叉、差异和对称差异等数学操作提供高速操作。::

>>> a = set('abracadabra')              # form a set from a string
>>> 'z' in a                            # fast membership testing
False
>>> a                                   # unique letters in a
set(['a', 'r', 'b', 'c', 'd'])
>>> ''.join(a)                          # convert back into a string
'arbcd'

>>> b = set('alacazam')                 # form a second set
>>> a - b                               # letters in a but not in b
set(['r', 'd', 'b'])
>>> a | b                               # letters in either a or b
set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'])
>>> a & b                               # letters in both a and b
set(['a', 'c'])
>>> a ^ b                               # letters in a or b but not both
set(['r', 'd', 'b', 'm', 'z', 'l'])

>>> a.add('z')                          # add a new element
>>> a.update('wxy')                     # add multiple new elements
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z'])
>>> a.remove('x')                       # take one element out
>>> a
set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z'])

这个 frozenset() 类型是的不可变版本 set() . 因为它是不可变的和可散列的,所以可以用作字典键或另一个集合的成员。

这个 sets 模块仍保留在标准库中,如果希望将 SetImmutableSet 类。目前没有计划取消预测该模块。

参见

PEP 218 -添加内置集合对象类型

最初由GregWilson提出,最终由RaymondHettinger实施。

PEP 237:统一长整数和整数

这个PEP的漫长过渡过程始于Python2.2,在Python2.4中又向前迈出了一步。在2.3中,在int/long统一触发后,某些整数操作的行为会有所不同。 FutureWarning 警告和返回值限制为32或64位(取决于您的平台)。在2.4中,这些表达式不再产生警告,而是产生一个通常为长整数的不同结果。

有问题的表达式主要是左移位和冗长的十六进制和八进制常量。例如, 2 << 32 结果在2.3中出现警告,在32位平台上评估为0。在python 2.4中,这个表达式现在返回正确的答案8589934592。

参见

PEP 237 -统一长整数和整数

由Moshe Zadka和Gvr编写的原始PEP。2.4的变更由Kalle Svensson实施。

PEP 289:生成器表达式

python 2.2中引入的迭代器特性和 itertools 模块使得编写循环大型数据集的程序变得更容易,而不必同时将整个数据集保存在内存中。列表理解不适合这个图片,因为它们生成一个包含所有项的python列表对象。这不可避免地会将所有对象都拖到内存中,如果数据集非常大,这可能是一个问题。当尝试编写一个功能性风格的程序时,很自然会编写如下内容:

links = [link for link in get_all_links() if not link.followed]
for link in links:
    ...

而不是::

for link in get_all_links():
    if link.followed:
        continue
    ...

第一个表单更简洁,也许更易读,但是如果您处理的是大量的链接对象,则必须编写第二个表单,以避免同时将所有链接对象保存在内存中。

生成器表达式的工作方式与列表理解类似,但不会具体化整个列表;相反,它们创建了一个生成器,将逐个返回元素。上面的例子可以写成:

links = (link for link in get_all_links() if not link.followed)
for link in links:
    ...

生成器表达式必须始终写在括号内,如上面的示例所示。指示函数调用的括号也会计数,因此如果要创建将立即传递给函数的迭代器,可以编写:

print sum(obj.count for obj in list_all_objects())

生成器表达式与列表理解的区别在于各种小的方面。最值得注意的是,循环变量( obj 在上面的示例中)在生成器表达式之外是不可访问的。列表理解将变量保留为其最后一个值;将来的Python版本将对此进行更改,使列表理解在这方面与生成器表达式匹配。

参见

PEP 289 -生成器表达式

由雷蒙德·赫廷格提出,由季原·seo实施,海世昌早期领导。

PEP 292:更简单的字符串替换

标准库中的一些新类提供了一种将变量替换为字符串的替代机制;这种替换方式对于未经培训的用户需要编辑模板的应用程序可能更好。

通常用名称替换变量的方法是 % 操作员:

>>> '%(page)i: %(title)s' % {'page':2, 'title': 'The Best of Times'}
'2: The Best of Times'

在编写模板字符串时,很容易忘记 is 在右括号之后。如果模板在python模块中,这不是一个大问题,因为您运行代码,得到一个“不支持的格式字符” ValueError 解决问题。但是,考虑一个应用程序,如mailman,其中模板字符串或翻译正由不了解Python语言的用户编辑。格式字符串的语法很难向这些用户解释,如果他们出错,很难向他们提供有用的反馈。

PEP 292增加了 Template 类到 string 使用的模块 $ 表示替换:

>>> import string
>>> t = string.Template('$page: $title')
>>> t.substitute({'page':2, 'title': 'The Best of Times'})
'2: The Best of Times'

如果字典中缺少键, substitute() 方法将引发 KeyError . 还有一个 safe_substitute() 忽略缺少键的方法::

>>> t = string.Template('$page: $title')
>>> t.safe_substitute({'page':3})
'3: $title'

参见

PEP 292 -更简单的字符串替换

由巴里·华沙撰写并实施。

PEP 318:功能和方法的装饰师

python 2.2通过添加静态方法和类方法扩展了python的对象模型,但它没有扩展python的语法来提供定义静态方法或类方法的任何新方法。相反,你必须写一个 def 以通常的方式声明,并将结果方法传递给 staticmethod()classmethod() 将函数封装为新类型的方法的函数。您的代码如下所示:

class C:
   def meth (cls):
       ...

   meth = classmethod(meth)   # Rebind name to wrapped-up class method

如果方法很长,很容易错过或忘记 classmethod() 函数体之后的调用。

其目的总是添加一些语法以使这些定义更具可读性,但在2.2发布时,良好的语法并不明显。今天语法不错 仍然 这并不明显,但用户要求更容易地访问该功能;已经添加了一个新的语法功能来满足这一需求。

新特性称为“函数修饰器”。这个名字来源于这样的想法 classmethod()staticmethod() 和朋友在函数对象上存储附加信息;他们 装饰 具有更多详细信息的函数。

符号从Java借用并使用 '@' 作为指示器的字符。使用新的语法,上面的示例将被写入:

class C:

   @classmethod
   def meth (cls):
       ...

这个 @classmethodmeth=classmethod(meth) 指派。一般来说,如果您有以下情况:

@A
@B
@C
def f ():
    ...

相当于以下预装饰代码:

def f(): ...
f = A(B(C(f)))

decorator必须位于函数定义之前的行上,每行一个decorator,并且不能与def语句位于同一行上,这意味着 @A def f(): ... 是非法的。您只能在模块级别或类内部修饰函数定义;不能修饰类定义。

decorator只是一个将要修饰的函数作为参数并返回同一个函数或某个新对象的函数。decorator的返回值不需要是可调用的(尽管它通常是可调用的),除非将对结果应用更多的decorator。写自己的装修师很容易。下面的简单示例只是在函数对象上设置一个属性:

>>> def deco(func):
...    func.attr = 'decorated'
...    return func
...
>>> @deco
... def f(): pass
...
>>> f
<function f at 0x402ef0d4>
>>> f.attr
'decorated'
>>>

作为一个更实际的例子,下面的decorator检查所提供的参数是否为整数:

def require_int (func):
    def wrapper (arg):
        assert isinstance(arg, int)
        return func(arg)

    return wrapper

@require_int
def p1 (arg):
    print arg

@require_int
def p2(arg):
    print arg*2

一个例子 PEP 318 包含此想法的更高级版本,允许您指定所需类型并检查返回的类型。

decorator函数可以接受参数。如果提供了参数,则只使用这些参数调用decorator函数,并且必须返回新的decorator函数;如前所述,此函数必须采用单个函数并返回函数。换言之, @A @B @C(args) 变成::

def f(): ...
_deco = C(args)
f = A(B(_deco(f)))

纠正这个错误可能会使大脑稍微弯曲,但并不太难。

一个小的相关变化使 func_name 函数的属性可写。此属性用于在回溯中显示函数名,因此装饰器应该更改已构造并返回的任何新函数的名称。

参见

PEP 318 -函数、方法和类的修饰符

作者:凯文·史密斯、吉姆·杰维特和斯基普·蒙塔纳罗。有几个人编写了实现函数修饰符的补丁,但实际上签入的是MarkRussell编写的补丁979728。

https://wiki.python.org/moin/PythonDecoratorLibrary

这个wiki页面包含几个装饰师的例子。

PEP 322:反向迭代

新的内置功能, reversed(seq) ,获取一个序列并返回以相反顺序循环序列元素的迭代器。::

>>> for i in reversed(xrange(1,4)):
...    print i
...
3
2
1

与扩展切片相比,例如 range(1,4)[::-1]reversed() 更容易阅读,运行速度更快,占用的内存更少。

注意 reversed() 只接受序列,不接受任意迭代器。如果要反转迭代器,请首先将其转换为具有 list() . ::

>>> input = open('/etc/passwd', 'r')
>>> for line in reversed(list(input)):
...   print line
...
root:*:0:0:System Administrator:/var/root:/bin/tcsh
  ...

参见

PEP 322 -反向迭代

由Raymond Hettinger编写并实施。

PEP 324:新的子流程模块

标准库提供了许多执行子流程的方法,提供了不同的特性和不同的复杂性级别。 os.system(command) 很容易使用,但是速度慢(它运行一个执行命令的shell进程)并且危险(您必须小心地转义shell的元字符)。这个 popen2 模块提供了可以从子进程捕获标准输出和标准错误的类,但是命名很混乱。这个 subprocess 模块将清除这一点,提供一个统一的接口,提供您可能需要的所有功能。

而不是 popen2 的类集合, subprocess 包含一个名为 Popen 其构造函数支持许多不同的关键字参数。::

class Popen(args, bufsize=0, executable=None,
            stdin=None, stdout=None, stderr=None,
            preexec_fn=None, close_fds=False, shell=False,
            cwd=None, env=None, universal_newlines=False,
            startupinfo=None, creationflags=0):

args 通常是作为子进程执行的程序的参数的字符串序列。(如果 参数是真的, args 可以是一个字符串,然后将其传递给shell进行解释,就像 os.system() 是吗?)

stdinstdoutstderr 指定子进程的输入、输出和错误流是什么。可以提供文件对象或文件描述符,也可以使用常量 subprocess.PIPE 在子进程和父进程之间创建管道。

构造函数有许多方便的选项:

  • close_fds 请求在运行子进程之前关闭所有文件描述符。

  • cwd 指定将在其中执行子进程的工作目录(默认为父进程的工作目录)。

  • env 是指定环境变量的字典。

  • preexec_fn 是在子级启动之前被调用的函数。

  • universal_newlines 使用python的 universal newlines 特征。

一旦你创建了 Popen 例如,您可以调用 wait() 方法暂停,直到子进程退出, poll() 检查它是否不停地退出,或者 communicate(data) 发送字符串 data 到子流程的标准输入。 communicate(data) 然后读取子进程发送到其标准输出或标准错误的任何数据,返回元组 (stdout_data, stderr_data) .

call() 是将其参数传递给 Popen 构造函数,等待命令完成,并返回子进程的状态代码。它可以作为一个更安全的模拟 os.system() ::

sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb'])
if sts == 0:
    # Success
    ...
else:
    # dpkg returned an error
    ...

调用命令时不使用shell。如果您真的想使用shell,可以添加 shell=True 作为关键字参数并提供字符串而不是序列:

sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True)

PEP采用了各种各样的shell和python代码示例,并展示了如何将它们转换为使用 subprocess . 强烈建议阅读本节的PEP。

参见

PEP 324 -子流程-新流程模块

由Peter_Strand在Fredrik Lundh和其他人的协助下编写和实施。

PEP 327:十进制数据类型

基于底层C,python始终支持浮点(fp)数字 double 类型,作为数据类型。然而,尽管大多数编程语言都提供浮点类型,但许多人(甚至程序员)都不知道浮点数字不能准确地表示某些小数部分。新的 Decimal 类型可以准确地表示这些分数,达到用户指定的精度限制。

为什么需要十进制?

这些限制来自用于浮点数的表示。FP编号由三个部分组成:

  • 正负的符号。

  • 尾数尾数,是一个单位二进制数,后跟一个小数部分。例如, 1.01 以2为基数的符号是 1 + 0/2 + 1/4 或1.25的十进制符号。

  • 指数,指示小数点在所表示的数字中的位置。

例如,数字1.25有正号,尾数值为1.01(二进制),指数为0(小数点不需要移位)。数字5有相同的符号和尾数,但指数是2,因为尾数乘以4(2乘以指数2的幂);1.25 * 4等于5。

现代系统通常提供符合IEEE754标准的浮点支持。C氏症 double 类型通常实现为64位IEEE754数字,尾数使用52位空间。这意味着数字只能被指定为52位的精度。如果您试图表示其扩展无限重复的数字,那么扩展将在52位之后被切断。不幸的是,大多数软件需要以10为基数生成输出,10为基数的普通分数通常以二进制形式重复小数。例如,1.1十进制是二进制的 1.0001100110011 ... ;.1=1/16+1/32+1/256加上无限个附加项。IEEE754必须在52位后切掉这个无限重复的十进制数,所以表示法有点不准确。

有时在打印号码时,您会看到这种不准确:

>>> 1.1
1.1000000000000001

当您打印数字时,不准确并不总是可见的,因为fp到decimal字符串的转换是由C库提供的,并且大多数C库都试图产生合理的输出。然而,即使不显示,误差仍然存在,随后的操作会放大误差。

对于许多应用来说,这并不重要。如果我正在绘制点并在监视器上显示它们,那么1.1和1.1000000000000001之间的差异太小,看不见。报告通常会将输出限制在一定的小数位数,如果将该数字四舍五入到两个或三个甚至八个小数位数,则错误永远不会明显。然而,对于那些确实很重要的应用程序,实现自己的自定义算术例程是一项非常繁重的工作。

因此, Decimal 类型已创建。

这个 Decimal 类型

一个新的模块, decimal ,添加到了Python的标准库中。它包含两个类, DecimalContext . Decimal 实例表示数字,以及 Context 实例用于封装各种设置,如精度和默认舍入模式。

Decimal 实例是不可变的,就像普通的python整数和fp数字一样;一旦创建了它,就不能更改实例所代表的值。 Decimal 可以使用整数或字符串创建实例:

>>> import decimal
>>> decimal.Decimal(1972)
Decimal("1972")
>>> decimal.Decimal("1.1")
Decimal("1.1")

还可以提供包含符号、尾数(表示为十进制数字的元组)和指数的元组:

>>> decimal.Decimal((1, (1, 4, 7, 5), -2))
Decimal("-14.75")

注意:符号位是一个布尔值,所以0是正的,1是负的。

从浮点数转换会带来一个问题:表示1.1的fp数应该变成精确的1.1的十进制数,还是1.1加上引入的任何不精确性?决定是回避这个问题,让这样的转换离开API。相反,您应该使用所需的精度将浮点数转换为字符串,并将字符串传递给 Decimal 构造器:

>>> f = 1.1
>>> decimal.Decimal(str(f))
Decimal("1.1")
>>> decimal.Decimal('%.12f' % f)
Decimal("1.100000000000")

一旦你拥有 Decimal 实例,您可以对它们执行常见的数学运算。一个限制:求幂需要整数求幂::

>>> a = decimal.Decimal('35.72')
>>> b = decimal.Decimal('1.73')
>>> a+b
Decimal("37.45")
>>> a-b
Decimal("33.99")
>>> a*b
Decimal("61.7956")
>>> a/b
Decimal("20.64739884393063583815028902")
>>> a ** 2
Decimal("1275.9184")
>>> a**b
Traceback (most recent call last):
  ...
decimal.InvalidOperation: x ** (non-integer)

你可以结合 Decimal 具有整数但不具有浮点数的实例::

>>> a + 4
Decimal("39.72")
>>> a + 4.5
Traceback (most recent call last):
  ...
TypeError: You can interact Decimal only with int, long or Decimal data types.
>>>

Decimal 数字可与 mathcmath 但请注意,在执行操作之前,它们将立即转换为浮点数,从而可能会导致精度和准确性的损失。你还可以得到一个普通的浮点数,而不是 Decimal . ::

>>> import math, cmath
>>> d = decimal.Decimal('123456789012.345')
>>> math.sqrt(d)
351364.18288201344
>>> cmath.sqrt(-d)
351364.18288201344j

Decimal 实例具有 sqrt() 返回 Decimal 但是如果你需要其他东西,比如三角函数,你就必须实现它们。::

>>> d.sqrt()
Decimal("351364.1828820134592177245001")

这个 Context 类型

的实例 Context 类封装了十进制操作的几个设置:

  • prec 是精度,是小数位数。

  • rounding 指定舍入模式。这个 decimal 模块具有各种可能性的常数: ROUND_DOWNROUND_CEILINGROUND_HALF_EVEN 以及其他各种各样的。

  • traps 是一个字典,指定在遇到某些错误条件时会发生什么:引发异常或返回值。错误条件的一些例子是被零除、精度损失和溢出。

通过调用 getcontext() ;可以更改此上下文的属性以更改默认精度、舍入或陷阱处理。以下示例显示更改默认上下文精度的效果:

>>> decimal.getcontext().prec
28
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.1428571428571428571428571429")
>>> decimal.getcontext().prec = 9
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal("0.142857143")

错误条件的默认操作是可选的;模块可以返回特殊值,如无穷大或非数字,或者引发异常:

>>> decimal.Decimal(1) / decimal.Decimal(0)
Traceback (most recent call last):
  ...
decimal.DivisionByZero: x / 0
>>> decimal.getcontext().traps[decimal.DivisionByZero] = False
>>> decimal.Decimal(1) / decimal.Decimal(0)
Decimal("Infinity")
>>>

这个 Context 实例还具有各种格式化数字的方法,例如 to_eng_string()to_sci_string() .

有关详细信息,请参阅 decimal 模块,其中包括快速入门教程和参考。

参见

PEP 327 -十进制数据类型

由Facando Batista编写,由Facando Batista、Eric Price、Raymond Hettinger、AAHZ和Tim Peters实施。

http://www.lahey.com/float.htm

本文使用Fortran代码来说明浮点不准确可能导致的许多问题。

http://speleotrove.com/decimal/

基于十进制表示的描述。这种表示被提议作为一种标准,并作为新的python decimal类型的基础。这些材料大部分是由雷克斯语言的设计师迈克·考利肖写的。

PEP 328:多行导入

一种语言变化是一种小的语法调整,旨在使从模块中导入多个名称更容易。在一个 from module import names 语句, 姓名 是用逗号分隔的名称序列。如果序列很长,可以从同一个模块中写入多个导入,也可以使用反斜杠来转义这样的行尾:

from SimpleXMLRPCServer import SimpleXMLRPCServer,\
            SimpleXMLRPCRequestHandler,\
            CGIXMLRPCRequestHandler,\
            resolve_dotted_attribute

python 2.4中的语法更改只允许将名称放在括号中。python忽略括号表达式中的换行符,因此不再需要反斜杠::

from SimpleXMLRPCServer import (SimpleXMLRPCServer,
                                SimpleXMLRPCRequestHandler,
                                CGIXMLRPCRequestHandler,
                                resolve_dotted_attribute)

PEP还建议 import 语句是绝对导入,带有前导 . 表示相对导入的字符。PEP的这一部分不是针对Python2.4实现的,而是针对Python2.5完成的。

参见

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

由AAHZ编写。多行导入由Dima Dorfman实现。

PEP 331:与区域无关的浮点/字符串转换

这个 locale 模块允许Python软件选择各种转换并显示本地化到特定国家或语言的约定。但是,模块小心地不更改数值区域设置,因为Python实现中的各种函数要求数值区域设置保持为 'C' locale。通常这是因为代码使用的是C库的 atof() 功能。

但是,没有设置数值区域设置会给使用第三方C库的扩展带来麻烦,因为它们没有正确的区域设置。激励人心的例子是GTK+,它的用户界面小部件没有在当前区域中显示数字。

PEP中描述的解决方案是向仅执行ASCII转换的python api添加三个新函数,忽略区域设置:

  • PyOS_ascii_strtod(str, ptr)PyOS_ascii_atof(str, ptr) 两者都将字符串转换为C double .

  • PyOS_ascii_formatd(buffer, buf_len, format, d) 转换A double 到一个ASCII字符串。

这些函数的代码来自于GLIB库(http://Dealth.GnOM.Org/GLUB/稳定/),其开发者友好地重新定义了相关函数并将其捐赠给Python软件基金会。这个 locale 模块现在可以更改数字区域设置,让GTK+等扩展产生正确的结果。

参见

PEP 331 -与区域设置无关的浮点/字符串转换

由Christian R.Reis撰写,Gustavo Carneiro实施。

其他语言更改

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

  • 增加了函数和方法的修饰器 (PEP 318

  • 内置的 set()frozenset() 添加了类型 (PEP 218 )其他新的内置组件包括 reversed(seq) 功能 (PEP 322

  • 添加了生成器表达式 (PEP 289

  • 某些数值表达式不再返回限制为32或64位的值 (PEP 237

  • 现在可以在 from module import names 陈述 (PEP 328

  • 这个 dict.update() 方法现在接受与 dict 构造函数。这包括任何映射、键/值对的任何ITable和关键字参数。(Raymond Hettinger提供。)

  • 字符串方法 ljust()rjust()center() 现在使用一个可选参数来指定填充字符而不是空格。(Raymond Hettinger提供。)

  • 字符串也获得了 rsplit() 工作方式与 split() 方法,但从字符串结尾拆分。(肖恩·雷夫施耐德供稿)::

    >>> 'www.python.org'.split('.', 1)
    ['www', 'python.org']
    'www.python.org'.rsplit('.', 1)
    ['www.python', 'org']
    
  • 三个关键字参数, cmpkeyreverse ,已添加到 sort() 列表方法。这些参数通常用于 sort() 更简单。所有这些参数都是可选的。

    对于 cmp 参数,该值应该是一个比较函数,它接受两个参数,并根据参数的比较方式返回-1、0或+1。然后将使用此函数对列表进行排序。以前,这是唯一可以提供给 sort() .

    key 应该是一个单参数函数,它接受一个列表元素并返回该元素的比较键。然后使用比较键对列表进行排序。以下示例不敏感地对列表大小写排序:

    >>> L = ['A', 'b', 'c', 'D']
    >>> L.sort()                 # Case-sensitive sort
    >>> L
    ['A', 'D', 'b', 'c']
    >>> # Using 'key' parameter to sort list
    >>> L.sort(key=lambda x: x.lower())
    >>> L
    ['A', 'b', 'c', 'D']
    >>> # Old-fashioned way
    >>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
    >>> L
    ['A', 'b', 'c', 'D']
    

    最后一个示例,它使用 cmp 参数,是执行不区分大小写排序的旧方法。它可以工作,但比使用 key 参数。使用 key 调用 lower() 方法对列表中的每个元素使用一次 cmp 每次比较将调用两次,因此使用 key 调用时保存 lower() 方法。

    对于简单的键函数和比较函数,通常可以避免 lambda 使用未绑定方法的表达式。例如,上面不区分大小写的排序最好写为:

    >>> L.sort(key=str.lower)
    >>> L
    ['A', 'b', 'c', 'D']
    

    最后, reverse 参数采用布尔值。如果该值为真,则列表将按相反顺序排序。而不是 L.sort(); L.reverse() ,你现在可以写了 L.sort(reverse=True) .

    现在,排序的结果保证是稳定的。这意味着两个具有相同键的条目将以与输入相同的顺序返回。例如,可以按姓名对人员列表进行排序,然后按年龄对列表进行排序,从而生成按年龄排序的列表,其中具有相同年龄的人员按姓名排序。

    ( 所有更改 sort() 由Raymond Hettinger提供。)

  • 有一个新的内置功能 sorted(iterable) 就像在原地一样 list.sort() 方法,但不能在表达式中使用。区别在于:

  • 输入可以是任何可重复的;

  • 对新形成的副本进行分类,使原始副本保持完整;以及

  • 表达式返回新的已排序副本

    >>> L = [9,7,8,3,2,4,1,6,5]
    >>> [10+i for i in sorted(L)]       # usable in a list comprehension
    [11, 12, 13, 14, 15, 16, 17, 18, 19]
    >>> L                               # original is left unchanged
    [9,7,8,3,2,4,1,6,5]
    >>> sorted('Monty Python')          # any iterable may be an input
    [' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y']
    
    >>> # List the contents of a dict sorted by key values
    >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5)
    >>> for k, v in sorted(colormap.iteritems()):
    ...     print k, v
    ...
    black 4
    blue 2
    green 3
    red 1
    yellow 5
    

    ( Raymond Hettinger提供。)

  • 整数运算将不再触发 OverflowWarning . 这个 OverflowWarning 警告将在python 2.5中消失。

  • 翻译得到一个新的开关, -m ,它取一个名称,在上搜索相应的模块 sys.path ,并以脚本形式运行模块。例如,现在可以使用 python -m profile . (尼克·科格伦供稿)

  • 这个 eval(expr, globals, locals)execfile(filename, globals, locals) 功能和 exec 语句现在接受 locals 参数。以前这必须是一个普通的python字典。(Raymond Hettinger提供。)

  • 这个 zip() 内置功能和 itertools.izip() 如果不带参数调用,现在返回一个空列表。以前他们养了一个 TypeError 例外。这使它们更适合用于可变长度参数列表:

    >>> def transpose(array):
    ...    return zip(*array)
    ...
    >>> transpose([(1,2,3), (4,5,6)])
    [(1, 4), (2, 5), (3, 6)]
    >>> transpose([])
    []
    

    ( Raymond Hettinger提供。)

  • 导入模块时遇到故障,将不再保留部分初始化的模块对象 sys.modules . 留下的不完整的模块对象将欺骗同一模块的进一步导入,从而导致混淆的错误。(由蒂姆·彼得斯修复)

  • None 现在是常量;将新值绑定到名称的代码 None 现在是语法错误。(Raymond Hettinger提供。)

优化

  • 列表和元组切片的内部循环得到了优化,现在运行速度快了三分之一。字典的内部循环也得到了优化,从而提高了 keys()values()items()iterkeys()itervalues()iteritems() . (Raymond Hettinger提供。)

  • 用于增加和缩小列表的机器针对速度和空间效率进行了优化。由于更高效的代码路径和对底层系统的不频繁使用,从列表中添加和弹出操作现在运行得更快。 realloc() . 列出理解也有好处。 list.extend() 也进行了优化,在扩展基列表之前不再将其参数转换为临时列表。(Raymond Hettinger提供。)

  • list()tuple()map()filter()zip() 现在,使用提供 __len__() 方法。(Raymond Hettinger提供。)

  • 方法 list.__getitem__()dict.__getitem__()dict.__contains__() 现在实现为 method_descriptor 对象而不是 wrapper_descriptor 物体。这种形式的访问将性能提高一倍,使其更适合用作功能的参数: map(mydict.__getitem__, keylist) . (Raymond Hettinger提供。)

  • 添加了新的操作码, LIST_APPEND 这就简化了生成的字节码来理解列表,并将其速度提高了大约三分之一。(Raymond Hettinger提供。)

  • 对窥视孔字节码优化器进行了改进,以生成更短、更快的字节码;值得注意的是,由此产生的字节码可读性更强。(由雷蒙德·赫廷格增强。)

  • 窗体语句中的字符串连接 s = s + "abc"s += "abc" 现在在某些情况下执行效率更高。这种优化不会出现在Jython等其他Python实现中,因此您不应该依赖它;使用 join() 当您希望有效地将大量字符串粘合在一起时,仍然建议使用字符串方法。(由Armin Rigo提供。)

2.4优化的最终结果是,pystone 2.4运行pystone基准比python 2.3快5%,比python 2.2快35%。(Pystone不是一个特别好的基准,但它是对Python性能最常用的度量。您自己的应用程序可能会从Python2.4中显示出更大或更小的好处。)

新的、改进的和不推荐使用的模块

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

  • 这个 asyncore 模块的 loop() 函数现在有一个 计数 参数,用于在轮询循环中执行有限数量的传递。默认值仍然是永远循环。

  • 这个 base64 模块现在更完整了 RFC 3548 支持base64、base32和base16编码和解码,包括可选的大小写折叠和可选的可选字母。(巴里·华沙供稿)

  • 这个 bisect 模块现在有一个底层的C实现来提高性能。(由Dmitry Vasiliev提供。)

  • 由hye shik chang维护的东亚编解码器的cjkcodecs集合集成到2.4中。新编码包括:

  • 中文(中国):GB2312、GBK、GB18030、Big5hkss、HZ

  • 中文(ROC):Big5,CP950

  • 日语:CP932,euc-jis-2004,euc-jp,euc-jisx0213,iso-2022-jp,

    ISO-2022-JP-1、ISO-2022-JP-2、ISO-2022-JP-3、ISO-2022-JP-ext、ISO-2022-JP-2004、shift-jis、shift-jisx0213、shift-jis-2004

  • 朝鲜语:CP949、EUC KR、Johab、ISO-2022-KR

  • 增加了其他一些新编码: HP Roman8, ISO_8859-11, ISO_8859-16, PCTP-154, and TIS-620.

  • UTF-8和UTF-16编解码器现在可以更好地处理接收部分输入。以前的 StreamReader 类将尝试读取更多数据,从而使无法从流中恢复解码。这个 read() 方法现在将返回尽可能多的数据,将来的调用将在以前的调用停止的地方恢复解码。(由Walter D_rwald实施。)

  • 有一种新的 collections 用于各种专用集合数据类型的模块。目前它只包含一种类型, deque ,一个双端队列,支持从任意一端高效地添加和删除元素::

    >>> from collections import deque
    >>> d = deque('ghi')        # make a new deque with three items
    >>> d.append('j')           # add a new entry to the right side
    >>> d.appendleft('f')       # add a new entry to the left side
    >>> d                       # show the representation of the deque
    deque(['f', 'g', 'h', 'i', 'j'])
    >>> d.pop()                 # return and remove the rightmost item
    'j'
    >>> d.popleft()             # return and remove the leftmost item
    'f'
    >>> list(d)                 # list the contents of the deque
    ['g', 'h', 'i']
    >>> 'h' in d                # search the deque
    True
    

    几个模块,如 Queuethreading 模块,现在利用 collections.deque 以提高性能。(Raymond Hettinger提供。)

  • 这个 ConfigParser 课程稍微提高了。这个 read() 方法现在返回成功分析的文件列表,以及 set() 方法抬高 TypeError 如果通过 value 不是字符串的参数。(约翰·贝尔蒙特和大卫·古德贡献)

  • 这个 curses 模块现在支持ncurses扩展 use_default_colors() .在终端支持透明的平台上,这使得使用透明的背景成为可能。(J_rg Lehmann提供)

  • 这个 difflib 模块现在包括 HtmlDiff 类,该类创建一个HTML表,显示文本的两个版本的并排比较。(丹·加斯供稿)

  • 这个 email 包被更新到3.0版,它删除了各种不推荐使用的API,并删除了对早于2.3版的Python版本的支持。包的3.0版本使用了新的用于mime消息的增量解析器,可在 email.FeedParser 模块。新的解析器不需要将整个消息读取到内存中,并且在消息格式不正确时不会引发异常;相反,它在 defect 消息的属性。(由Anthony Baxter、Barry Warsaw、Thomas Wouters等开发)

  • 这个 heapq 模块已转换为C。速度提高了10倍,使模块适合处理大量数据。此外,该模块还有两个新功能 nlargest()nsmallest() 它使用堆来查找数据集中的n个最大或最小值,而不需要花费完全排序的费用。(Raymond Hettinger提供。)

  • 这个 httplib 模块现在包含在各种HTTP相关的RFC文档中定义的HTTP状态代码的常量。常量的名称如下 OKCREATEDCONTINUEMOVED_PERMANENTLY ;使用pydoc获取完整列表。(安德鲁伊兰供稿)

  • 这个 imaplib 模块现在支持imap的thread命令(由yves dionne提供)和new deleteacl()myrights() 方法(由Arnaud Mazin提供)。

  • 这个 itertools 模块获得 groupby(iterable[, *func*]) 功能。 可迭代的 是可以迭代以返回元素流的内容,并且 func 参数是一个接受元素并返回键值的函数;如果省略,则键只是元素本身。 groupby() 然后将元素分组为具有匹配键值的子序列,并返回一系列包含键值的2元组和子序列上的迭代器。

    下面是一个更清晰的例子。这个 key 函数只返回一个数是偶数还是奇数,因此 groupby() 是返回奇数或偶数的连续运行。地址:

    >>> import itertools
    >>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14]
    >>> for key_val, it in itertools.groupby(L, lambda x: x % 2):
    ...    print key_val, list(it)
    ...
    0 [2, 4, 6]
    1 [7]
    0 [8]
    1 [9, 11]
    0 [12, 14]
    >>>
    

    groupby() 通常用于已排序的输入。逻辑 groupby() 类似于Unix uniq 便于消除、计数或识别重复元素的筛选器:

    >>> word = 'abracadabra'
    >>> letters = sorted(word)   # Turn string into a sorted list of letters
    >>> letters
    ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
    >>> for k, g in itertools.groupby(letters):
    ...    print k, list(g)
    ...
    a ['a', 'a', 'a', 'a', 'a']
    b ['b', 'b']
    c ['c']
    d ['d']
    r ['r', 'r']
    >>> # List unique letters
    >>> [k for k, g in groupby(letters)]
    ['a', 'b', 'c', 'd', 'r']
    >>> # Count letter occurrences
    >>> [(k, len(list(g))) for k, g in groupby(letters)]
    [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]
    

    ( 许惠世供稿)

  • itertools 还获得了一个名为 tee(iterator, N) 它会回来 N 复制的独立迭代器 迭代器 . 如果 N 省略,默认值为2。::

    >>> L = [1,2,3]
    >>> i1, i2 = itertools.tee(L)
    >>> i1,i2
    (<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>)
    >>> list(i1)               # Run the first iterator to exhaustion
    [1, 2, 3]
    >>> list(i2)               # Run the second iterator to exhaustion
    [1, 2, 3]
    

    注意 tee() 必须保留迭代器返回的值的副本;在最坏的情况下,它可能需要保留所有这些值。因此,如果前面的迭代器可以在长的输入流中远远领先于后面的迭代器,那么应该小心使用它。如果分离度很大,那么您也可以使用 list() 相反。当迭代器彼此紧密跟踪时, tee() 是理想的。可能的应用程序包括书签、窗口或lookahead迭代器。(Raymond Hettinger提供。)

  • 许多函数被添加到 locale 模块,如 bind_textdomain_codeset() 指定特定编码和 l*gettext() 以所选编码返回消息的函数。(古斯塔沃·尼迈耶供稿)

  • 一些关键字参数已添加到 logging 封装的 basicConfig() 函数来简化日志配置。默认行为是将消息记录到标准错误,但是可以指定各种关键字参数以记录到特定文件、更改日志格式或设置日志级别。例如::

    import logging
    logging.basicConfig(filename='/var/log/application.log',
        level=0,  # Log all messages
        format='%(levelname):%(process):%(thread):%(message)')
    

    其他添加到 logging 封装包括 log(level, msg) 方便方法,以及 TimedRotatingFileHandler 类,该类按时间间隔旋转其日志文件。模块已经 RotatingFileHandler ,一旦文件超过某个大小,就会旋转日志。这两个类都源于一个新的 BaseRotatingHandler 可用于实现其他旋转处理程序的类。

    ( Vinay Sajip实施的变更。)

  • 这个 marshal 模块现在在解包数据结构时共享内部字符串。这可能会缩小某些泡菜串的大小,但主要效果是 .pyc 文件要小得多。(马丁·冯·L·威斯供稿)

  • 这个 nntplib 模块的 NNTP 获得阶级 description()descriptions() 方法检索单个组或一系列组的新闻组说明。(J_rgen A.Erhard提供)

  • 添加了两个新函数 operator 模块, attrgetter(attr)itemgetter(index) . 这两个函数都返回接受单个参数的可调用文件,并返回相应的属性或项;这些可调用文件在与 map()sorted() . 例如::

    >>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)]
    >>> map(operator.itemgetter(0), L)
    ['c', 'd', 'a', 'b']
    >>> map(operator.itemgetter(1), L)
    [2, 1, 4, 3]
    >>> sorted(L, key=operator.itemgetter(1)) # Sort list by second tuple item
    [('d', 1), ('c', 2), ('b', 3), ('a', 4)]
    

    ( Raymond Hettinger提供。)

  • 这个 optparse 模块以各种方式更新。模块现在通过 gettext.gettext() 使optik的帮助和错误消息国际化成为可能。选项的帮助消息现在可以包含字符串 '%default' ,将替换为选项的默认值。(格雷格·沃德供稿)

  • 长期计划是对 rfc822 在将来的某个python版本中,模块支持 email 包裹。为此, email.Utils.formatdate() 函数已更改,以使其可用作 rfc822.formatdate() . 您可能需要记住这一点来编写新的电子邮件处理代码。(由Anthony Baxter实施变更。)

  • 一个新的 urandom(n) 函数已添加到 os 模块,返回包含 n 随机数据字节。此功能提供对平台特定随机性源的访问,例如 /dev/urandom 在Linux或Windows CryptoAPI上。(特雷弗·佩林供稿)

  • 另一个新功能: os.path.lexists(path) 如果指定的文件 path 存在,不管它是否是符号链接。这与现有的不同 os.path.exists(path) 函数,如果 path 是指向不存在的目标的符号链接。(贝尼·切尼亚夫斯基供稿)

  • 一个新的 getsid() 函数已添加到 posix 构成 os 模块。(J.Raynor供稿)

  • 这个 poplib 模块现在支持pop over ssl。(赫克托·乌图比亚供稿)

  • 这个 profile 模块现在可以分析C扩展函数。(尼克·巴斯汀供稿)

  • 这个 random 模块有一个新方法调用 getrandbits(N) 返回一个长整数 N 位的长度。现有的 randrange() 方法现在使用 getrandbits() 在适当的情况下,使任意大的随机数的生成更有效。(Raymond Hettinger提供。)

  • 所接受的正则表达式语言 re 模块是用简单的条件表达式扩展的,编写为 (?(group)A|B) . group 是数字组ID或用定义的组名 (?P<group>...) 在表达式的前面。如果指定的组匹配,则正则表达式模式 A 将根据字符串进行测试;如果组不匹配,则模式 B 将改为使用。(古斯塔沃·尼迈耶供稿)

  • 这个 re 由于GustavoNiemeyer的大量工作,模块也不再是递归的。在递归正则表达式引擎中,某些模式会导致大量的C堆栈空间被占用,并且可能溢出堆栈。例如,如果您匹配一个30000字节的字符串 a 与表达式相对应的字符 (a|b)+ ,每个字符消耗一个堆栈帧。python 2.3试图检查堆栈溢出并引发 RuntimeError 例外,但某些模式可能会回避检查,如果您不幸的话,python可能会出错。Python2.4的正则表达式引擎可以毫无问题地匹配这个模式。

  • 这个 signal 模块现在对 signal.signal() 功能。例如,不能在 SIGKILL 信号;以前版本的python会悄悄地接受这一点,但2.4将引发 RuntimeError 例外。

  • 添加了两个新函数 socket 模块。 socketpair() 返回一对已连接的套接字和 getservbyport(port) 查找给定端口号的服务名称。(由戴夫·科尔和巴里·华沙提供。)

  • 这个 sys.exitfunc() 函数已被弃用。代码应该使用现有的 atexit 模块,正确处理调用多个出口函数。最终 sys.exitfunc() 将成为一个纯粹的内部接口,只有 atexit .

  • 这个 tarfile 模块现在默认生成GNU格式的tar文件。(拉尔斯·古斯特·贝尔供稿)

  • 这个 threading 模块现在有了一个优雅简单的方法来支持线程本地数据。该模块包含 local 属性值对不同线程是本地的类。::

    import threading
    
    data = threading.local()
    data.number = 42
    data.url = ('www.python.org', 80)
    

    其他线程可以为 numberurl 属性。您可以子类 local 初始化属性或添加方法。(吉姆·富尔顿贡献)

  • 这个 timeit 模块现在自动禁用定时循环期间的定期垃圾收集。这一变化使得连续计时更具可比性。(Raymond Hettinger提供。)

  • 这个 weakref 模块现在支持各种各样的对象,包括python函数、类实例、集合、frozenset、deques、数组、文件、套接字和正则表达式模式对象。(Raymond Hettinger提供。)

  • 这个 xmlrpclib 模块现在支持在单个HTTP操作中传输多个XML-RPC调用的多调用扩展。(布莱恩·昆兰供稿)

  • 这个 mpzrotorxreadlines 模块已被移除。

库基里布

这个 cookielib 库支持HTTP cookie的客户端处理,镜像 Cookie 模块的服务器端cookie支持。cookie存储在cookie jar中;库将Web服务器提供的cookie透明地存储在cookie jar中,并在连接到服务器时从jar中获取cookie。与Web浏览器一样,策略对象控制是否接受cookie。

为了跨会话存储cookie,提供了两个cookie jar实现:一个以Netscape格式存储cookie,以便应用程序可以使用Mozilla或Lynx cookie文件,另一个以与Perl libwww库相同的格式存储cookie。

urllib2 已更改为与 cookielibHTTPCookieProcessor 管理访问URL时使用的cookie jar。

本单元由约翰·J·李撰稿。

doctest

这个 doctest 多亏了爱德华·洛珀和蒂姆·彼得斯,模块经历了相当大的重构。测试仍然可以像运行一样简单 doctest.testmod() 但是重构允许以各种方式自定义模块的操作

新的 DocTestFinder 类从给定对象的docStrings提取测试:

def f (x, y):
    """>>> f(2,2)
4
>>> f(3,2)
6
    """
    return x*y

finder = doctest.DocTestFinder()

# Get list of DocTest instances
tests = finder.find(f)

新的 DocTestRunner 然后,类运行单个测试,并可以生成结果的摘要:

runner = doctest.DocTestRunner()
for t in tests:
    tried, failed = runner.run(t)

runner.summarize(verbose=1)

上面的示例生成以下输出:

1 items passed all tests:
   2 tests in f
2 tests in 1 items.
2 passed and 0 failed.
Test passed.

DocTestRunner 使用的实例 OutputChecker 类来比较预期输出和实际输出。这个类采用许多不同的标志来定制它的行为;雄心勃勃的用户还可以编写一个全新的子类 OutputChecker .

默认的输出检查器提供了许多方便的功能。例如,使用 doctest.ELLIPSIS 选项标志,省略号 (... )在预期的输出与任何子字符串匹配时,更容易适应以较小方式变化的输出:

def o (n):
    """>>> o(1)
<__main__.C instance at 0x...>
>>>
"""

另一个特殊的字符串, <BLANKLINE> ,匹配空行:

def p (n):
    """>>> p(1)
<BLANKLINE>
>>>
"""

另一个新功能是通过指定 doctest.REPORT_UDIFF (统一差异) doctest.REPORT_CDIFF (上下文差异),或 doctest.REPORT_NDIFF (Delta样式)选项标志。例如::

def g (n):
    """>>> g(4)
here
is
a
lengthy
>>>"""
    L = 'here is a rather lengthy list of words'.split()
    for word in L[:n]:
        print word

使用运行上述函数的测试 doctest.REPORT_UDIFF 指定后,将得到以下输出:

**********************************************************************
File "t.py", line 15, in g
Failed example:
    g(4)
Differences (unified diff with -expected +actual):
    @@ -2,3 +2,3 @@
     is
     a
    -lengthy
    +rather
**********************************************************************

构建和C API更改

对Python构建过程和C API的一些更改是:

  • 为扩展函数的公共返回值添加了三个新的便利宏: Py_RETURN_NONEPy_RETURN_TRUEPy_RETURN_FALSE . (布雷特·坎农供稿)

  • 另一个新宏, Py_CLEAR(obj) ,减少的引用计数 objobj 指向空指针。(吉姆·富尔顿贡献)

  • 新功能, PyTuple_Pack(N, obj1, obj2, ..., objN) ,从python对象的可变长度参数列表构造元组。(Raymond Hettinger提供。)

  • 新功能, PyDict_Contains(d, k) 实现快速字典查找,而不屏蔽查找过程中引发的异常。(Raymond Hettinger提供。)

  • 这个 Py_IS_NAN(X) 如果宏的float或double参数为 X 是一个南。(蒂姆·彼得斯供稿)

  • C代码可以通过使用新的 PyEval_ThreadsInitialized() 函数来判断是否执行了任何线程操作。如果此函数返回false,则不需要进行锁操作。(尼克·科格伦供稿)

  • 新功能, PyArg_VaParseTupleAndKeywords() ,与 PyArg_ParseTupleAndKeywords() 但需要一个 va_list 而不是多个参数。(格雷格·查普曼供稿)

  • 新方法标志, METH_COEXISTS ,允许槽中定义的函数与 PyCFunction 有相同的名字。这可以将诸如 set.__contains__() . (Raymond Hettinger提供。)

  • 现在,可以为解释器本身使用附加的分析来构建Python,以帮助开发Python核心。提供 --enable-profilingconfigure 脚本将允许您使用 gprof ,并提供 --with-tsc 开关使用Pentium的时间戳计数器寄存器启用分析。请注意 --with-tsc 开关的名称有点错误,因为概要分析功能也可以在PowerPC平台上工作,尽管处理器体系结构没有将该寄存器称为“TSC寄存器”。(杰里米·希尔顿供稿)

  • 这个 tracebackobject 类型已重命名为 PyTracebackObject .

端口特定更改

  • Windows端口现在在MSVC++7.1和版本6下构建。(马丁·冯·L·威斯供稿)

移植到python 2.4

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

  • 太大的左移位和十六进制/八进制常量不再触发 FutureWarning 并返回一个限制为32或64位的值;相反,它们返回一个长整数。

  • 整数运算将不再触发 OverflowWarning . 这个 OverflowWarning 警告将在python 2.5中消失。

  • 这个 zip() 内置功能和 itertools.izip() 现在返回空列表,而不是引发 TypeError 如果调用时没有参数,则出现异常。

  • 你不能再比较 datedatetime 由提供的实例 datetime 模块。不同类的两个实例现在总是不相等的,并且是相对比较 (<> 将提高 TypeError .

  • dircache.listdir() 现在将异常传递给调用方,而不是返回空列表。

  • LexicalHandler.startDTD() 用于以错误的顺序接收公共ID和系统ID。这已得到纠正;依赖于错误顺序的应用程序需要修复。

  • fcntl.ioctl() 现在警告如果 突变 参数被省略并相关。

  • 这个 tarfile 模块现在默认生成GNU格式的tar文件。

  • 导入模块时遇到故障,将不再保留部分初始化的模块对象 sys.modules .

  • None 现在是常量;将新值绑定到名称的代码 None 现在是语法错误。

  • 这个 signals.signal() 函数现在引发 RuntimeError 某些非法值的例外情况;以前这些错误将静默传递。例如,不能再在 SIGKILL 信号。

确认

作者感谢以下人士对本文的各种草稿提出建议、更正和帮助:Koray Can、Hye Shik Chang、Michael Dyck、Raymond Hettinger、Brian Hurt、Hamish Lawson、Fredrik Lundh、Sean Reifschneider、Sadraddin Rejeb。