What’s New in Python 2.4

作者:上午。 Kuchling

本文介绍了2005年3月30日发布的Python 2.4.1中的新功能。

Python 2.4是一个中型版本。它不引入与激进Python 2.2一样多的变化,但引入了比保守的2.3版本更多的功能。最重要的新语言特性是函数装饰器和生成器表达式;大多数其他更改是标准库。

根据CVS更改日志,在Python 2.3和2.4之间应用了481个修补程序,修复了502个错误。这两个数字都可能是低估。

本文不试图提供每个新功能的完整规范,而是提供每个功能的简要介绍。有关详细信息,请参阅Python 2.4的文档,例如Python库参考和Python参考手册。通常,您将被引用到PEP一个特定的新功能的解释的实现和设计理由。

PEP 218: Built-In Set Objects

Python 2.3引入了sets模块。集合数据类型的C实现现在已经作为两个新的内建类型set(iterable)frozenset(iterable)添加到Python核心。它们为成员资格测试提供高速操作,用于从序列中消除重复,以及用于数学运算,如联合,交集,差异和对称差异。

>>> 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 - 添加内建集对象类型
最初由Greg Wilson提出,最终由Raymond Hettinger实施。

PEP 237: Unifying Long Integers and Integers

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

有问题的表达式主要是左移和长十六进制和八进制常数。例如,2 32会在2.3中产生警告,位平台。在Python 2.4中,这个表达式现在返回正确的答案,8589934592。

也可以看看

PEP 237 - 统一长整数和整数
由Moshe Zadka和GvR编写的原始PEP。2.4的变化由Kalle Svensson执行。

PEP 289: Generator Expressions

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 - 生成器表达式
由Raymond Hettinger提出,由Jiwon Seo执行,由Hye-Shik Chang领导的早期努力。

PEP 292: Simpler String Substitutions

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

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

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

当写模板字符串时,可以很容易地忽略右括号之后的is如果模板在Python模块中,这不是一个大问题,因为您运行代码,获取“不支持的格式字符”ValueError,并解决问题。但是,考虑一个应用程序,如Mailman,其中正在由不知道Python语言的用户编辑模板字符串或翻译。格式字符串的语法对这样的用户来说很复杂,如果他们犯了错误,很难向他们提供有用的反馈。

PEP 292向使用$string模块添加Template类来表示替换:

>>> 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 - 更简单的字符串替换
由Barry华沙撰写和实施。

PEP 318: Decorators for Functions and Methods

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

装饰器必须在函数定义之前行,每行一个装饰器,并且不能与def语句在同一行,意味着@A def f(): ...是非法的。你只能在模块级或类中装饰函数定义;你不能装饰类定义。

装饰器只是一个函数,它将要装饰的函数作为参数,并返回相同的函数或一些新的对象。装饰器的返回值不需要是可调用的(虽然它通常是),除非将另外的装饰器应用于结果。编写自己的装饰器很容易。以下简单示例只是在函数对象上设置一个属性:

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

作为一个稍微更现实的例子,下面的装饰器检查提供的参数是一个整数:

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中的示例包含此构思的一个更精彩的版本,可让您指定所需的类型并检查返回的类型。

装饰函数可以接受参数。如果提供参数,你的装饰器函数只调用这些参数,并且必须返回一个新的装饰器函数;此函数必须采用单个函数并返回一个函数,如前所述。换句话说,@A @B @C(args)

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

获得这个权利可以稍微弯曲,但它不是太困难。

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

也可以看看

PEP 318 - 函数,方法和类的装饰器
作者:Kevin D. Smith,Jim Jewett和Skip Montanaro。几个人写了补丁实现函数装饰器,但实际检查的补丁是补丁#979728,由马克·罗素写。
https://wiki.python.org/moin/PythonDecoratorLibrary
此Wiki页面包含装饰器的几个示例。

PEP 322: Reverse Iteration

新的内建函数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: New subprocess Module

标准库提供了执行子过​​程的多种方法,提供不同的特征和不同级别的复杂性。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通常是一串字符串,它们将作为作为子进程执行的程序的参数。(如果shell参数为真,则args可以是一个字符串,然后将其传递给shell进行解释,就像os.system()

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

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

  • close_fds请求在运行子过程之前关闭所有文件描述器。
  • cwd指定将执行子流程的工作目录(默认为父工作目录所在的工作目录)。
  • env是一个指定环境变量的字典。
  • preexec_fn是在子程序启动之前调用的函数。
  • universal_newlines使用Python的universal newlines功能打开孩子的输入和输出。

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

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的Python代码。强烈建议阅读PEP的这一部分。

也可以看看

PEP 324 - 子过程 - 新的过程模块
由PeterÅstrand在Fredrik Lundh和其他人的帮助下编写和实施。

PEP 327: Decimal Data Type

Python一直支持基于底层C double类型的浮点(FP)数字作为数据类型。然而,尽管大多数编程语言提供了浮点类型,但许多人(即使是程序员)也不知道浮点数不能精确地表示某些小数。新的Decimal类型可以精确表示这些分数,直到用户指定的精度限制。

Why is Decimal needed?

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

  • 符号,正数或负数。
  • 尾数,它是一个单位数的二进制数,后跟小数部分。例如,基2记号中的1.011 + 0/2 1/4,或十进制表示法的1.25。
  • 指数,指示小数点位于所表示的数字中的位置。

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

现代系统通常提供符合称为IEEE 754的标准的浮点支持。C的double类型通常实现为64位IEEE 754号码,它使用52位空间用于尾数。这意味着数字只能指定为52位精度。如果您试图表示其扩展不断重复的数字,则扩展将在52位之后中断。不幸的是,大多数软件需要产生基数为10的输出,而基数10中的公用分数通常是二进制的重复小数。例如,1.1十进制是二进制1.0001100110011 ...; .1 = 1/16 + 1/32 + 1/256加上无限数量的附加项。IEEE 754必须在52位数之后切断无限重复的十进制,因此表示略有不准确。

有时你可以看到这个不准确的数字打印时:

>>> 1.1
1.1000000000000001

当打印数字时,不准确性并不总是可见的,因为FP到十字符串转换是由C库提供的,大多数C库试图产生合理的输出。即使它不显示,但是不准确仍然存在,随后的操作可以放大错误。

对于许多应用程序,这没有关系。如果我绘制点并在我的显示器上显示它们,1.1和1.1000000000000001之间的差异太小,不可见。报告通常将输出限制到一定数目的小数位,如果将数舍入到两个或三个或甚至八个小数位,则错误不会明显。然而,对于有用的应用程序,实现自己的自定义算术程序需要做很多工作。

因此,创建了Decimal类型。

The Decimal type

A new module, decimal, was added to Python’s standard library. 它包含两个类,DecimalContextDecimal实例表示数字,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为负。

从浮点数转换提出了一个问题:如果FP代表1.1转为十进制数正好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实例具有返回Decimalsqrt()方法,但如果需要其他功能,例如三角函数,他们。

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

The Context type

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 - 十进制数据类型
由Facundo Batista撰写,由Facundo Batista,Eric Price,Raymond Hettinger,Aahz和Tim Peters执行。
http://www.lahey.com/float.htm
本文使用Fortran代码来说明浮点不准确性可能导致的许多问题。
http://speleotrove.com/decimal/
基于小数的表示形式的描述。这个表示被提出作为一个标准,并且是新的Python十进制类型的基础。这些材料大部分是由Rexx语言的设计师Mike Cowlishaw撰写的。

PEP 328: Multi-line Imports

一个语言变化是一个小的句法调整,目的在于更容易从模块导入许多名称。In a from module import names statement, names is a sequence of names separated by commas. 如果序列很长,您可以从同一个模块写入多个导入,也可以使用反斜杠转义行尾,如下所示:

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的这部分没有为Python 2.4实现,但是为Python 2.5完成。

也可以看看

PEP 328 - 导入:多行和绝对/相对
作者:Aahz。多线进口由Dima Dorfman实施。

PEP 331: Locale-Independent Float/String Conversions

locale模块可让Python软件选择本地化到特定国家或语言的各种转换和显示约定。但是,模块很小心不改变数字区域设置,因为Python实现中的各种函数需要数字区域设置仍然设置为'C'语言环境。通常这是因为代码使用了C库的atof()函数。

不是设置数字区域设置导致使用第三方C库的扩展的麻烦,因为它们不会有正确的区域设置。激励的例子是GTK +,其用户界面小部件不在当前语言环境中显示数字。

PEP中描述的解决方案是向Python API添加三个新函数,执行纯ASCII转换,忽略语言环境设置:

  • PyOS_ascii_strtod(str, ptr)PyOS_ascii_atof(str, ptr) t5 >都将字符串转换为C double
  • PyOS_ascii_formatd(buffer, buf_len, format, d) converts a double to an ASCII string.

这些函数的代码来自GLib库(https://developer.gnome.org/glib/stable/),它们的开发人员重新授权相关函数并将它们捐赠给Python软件基金会。locale模块现在可以更改数字语言环境,使诸如GTK +之类的扩展程序可以产生正确的结果。

也可以看看

PEP 331 - 与区域无关的浮点数/字符串转换
由Christian R. Reis撰写,由Gustavo Carneiro执行。

Other Language Changes

这里是Python 2.4对核心Python语言所做的所有更改。

  • 添加了函数和方法的装饰器( PEP 318)。

  • 内建set()frozenset()类型( PEP 218)。其他新内置函数包括reversed(seq)函数( PEP 322)。

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

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

  • 现在,您可以在 模块 导入 名称 t0 >语句( PEP 328)。

  • dict.update()方法现在接受与dict构造函数相同的参数形式。这包括任何映射,任何可迭代的键/值对和关键字参数。(由Raymond Hettinger提供)

  • 字符串方法ljust()rjust()center()现在使用可选参数指定空格以外的填充字符。(由Raymond Hettinger提供)

  • 字符串还获得了一个rsplit()方法,该方法类似于split()方法,但是从字符串的末尾开始分割。(供稿人:Sean Reifschneider。)

    >>> 'www.python.org'.split('.', 1)
    ['www', 'python.org']
    'www.python.org'.rsplit('.', 1)
    ['www.python', 'org']
    
  • 将三个关键字参数cmp反转添加到列表的sort()这些参数使得sort()的一些常见用法更简单。所有这些参数都是可选的。

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

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

    >>> 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参数的示例是执行不区分大小写排序的旧方法。它工作,但比使用参数慢。在使用cmp时,使用对列表中的每个元素调用lower()方法两次,因此使用保存lower()方法的调用。

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

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

    最后,reverse参数采用布尔值。如果值为true,将按照相反的顺序对列表进行排序。代替L.sort(); L.reverse(),现在可以写L.sort(reverse=True)

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

    (由Raymond Hettinger贡献的对sort()的所有更改。)

  • 有一个新的内建函数sorted(iterable),它像in-place 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在Python 2.5中,OverflowWarning警告将消失。

  • 解释器获得了一个新开关,-m,它获取一个名称,在sys.path上搜索相应的模块,并将该模块作为脚本运行。例如,您现在可以使用python -m 个人资料运行Python分析器。(由Nick Coghlan提供)

  • The eval(expr, globals, locals) and execfile(filename, globals, locals) functions and the exec statement now accept any mapping type for the locals parameter. 以前,这必须是一个常规的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中留下部分初始化的模块对象。不完整的模块对象留下将愚弄进一步导入相同的模块成功,导致混乱的错误。(由Tim Peters修正。)

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

Optimizations

  • 列表和元组切片的内循环已优化,现在运行大约三分之一。字典的内循环也被优化,导致keys()values()items()iterkeys()itervalues()iteritems()(由Raymond Hettinger提供)
  • 用于生长和收缩列表的机械被优化用于速度和空间效率。由于更高效的代码路径和较不频繁地使用底层系统realloc(),从列表中追加和弹出现在运行速度更快。列表推导式也受益。list.extend()也已优化,并且在扩展基本列表之前不再将其参数转换为临时列表。(由Raymond Hettinger提供)
  • list()tuple()map()filter()zip()现在使用提供__len__()方法的非序列参数运行几倍。(由Raymond Hettinger提供)
  • The methods list.__getitem__(), dict.__getitem__(), and dict.__contains__() are now implemented as method_descriptor objects rather than wrapper_descriptor objects. 这种访问形式使它们的性能加倍,使它们更适合用作函数的参数:map(mydict .__ getitem __, keylist)(由Raymond Hettinger提供)
  • 添加了一个新的操作码LIST_APPEND,可简化列表推导式生成的字节码,并将其加速约三分之一。(由Raymond Hettinger提供)
  • 窥视孔字节码优化器已经改进以产生更短,更快的字节码;显着地,所得到的字节码更可读。(由Raymond Hettinger强化)
  • 形式s = s + “abc” t5>s + = “abc”这种优化不会出现在其他Python实现,如Jython,所以你不应该依赖它;使用join()方法的字符串仍然建议,当你想有效地粘合大量的字符串在一起。(供稿人:Armin Rigo。)

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

New, Improved, and Deprecated Modules

像往常一样,Python的标准库收到了一些增强和错误修复。这里是最显着的变化的部分列表,按模块名称按字母顺序排序。请参阅源树中的Misc/NEWS文件以获取更完整的更改列表,或查看CVS日志以了解所有详细信息。

  • asyncore模块的loop()函数现在有一个count参数,允许您通过轮询循环执行有限次数的遍历。默认是仍然循环。

  • base64模块现在有更完整的RFC 3548支持Base64,Base32和Base16编码和解码,包括可选的案例折叠和可选的替代字母表。(由Barry Warsaw提供)

  • bisect模块现在具有底层C实现以提高性能。(供稿人:Dmitry Vasiliev。)

  • 由Hye-Shik Chang维护的东亚编解码器的CJKCodecs容器被集成到2.4。新的编码是:

  • 中国(PRC):gb2312,gbk,gb18030,big5hkscs,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, jis-2004

  • 韩语:cp949,euc-kr,johab,iso-2022-kr

  • 添加了一些其他新的编码:HP Roman8,ISO_8859-11,ISO_8859-16,PCTP-154和TIS-620。

  • UTF-8和UTF-16编解码器现在可以更好地接收部分输入。以前,StreamReader类将尝试读取更多数据,从而无法从流中恢复解码。read()方法现在将返回尽可能多的数据,并且未来的调用将恢复解码,其中先前的调用被停止。(由WalterDö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类已略有增强。The read() method now returns a list of the files that were successfully parsed, and the set() method raises TypeError if passed a value argument that isn’t a string. (由John Belmonte和David Goodger提供。)

  • curses模块现在支持ncurses扩展use_default_colors()在终端支持透明度的平台上,这使得可以使用透明背景。(供稿人:JörgLehmann。)

  • difflib模块现在包括一个HtmlDiff类,它创建一个HTML表格,显示文本的两个版本的并行比较。(供稿:Dan Gass。)

  • 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获取完整列表。(供稿:Andrew Eland。)

  • imaplib模块现在支持IMAP的THREAD命令(由Yves Dionne提供)和新的deleteacl()myrights()

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

    这里有一个例子,使这个更清楚。函数只返回数字是偶数还是奇数,因此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)]
    

    (由Hye-Shik Chang提供)

  • itertools还获得了返回N的名为tee(iterator, 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()(供稿人:Gustavo Niemeyer。)

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

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

    Other additions to the logging package include a log(level, msg) convenience method, as well as a TimedRotatingFileHandler class that rotates its log files at a timed interval. 模块已经具有RotatingFileHandler,它会在文件超出一定大小后轮换日志。这两个类派生自一个新的BaseRotatingHandler类,可用于实现其他旋转处理程序。

    (由Vinay Sajip执行的更改)

  • marshal模块现在在分拆数据结构时共享内部字符串。This may shrink the size of certain pickle strings, but the primary effect is to make .pyc files significantly smaller. (供稿:Martin vonLöwis。)

  • nntplib模块的NNTP类获取description()descriptions()(供稿人:JürgenA.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',将替换为选项的默认值。(由Greg Ward提供)

  • 长期计划是在将来的某个Python版本中取消rfc822模块,以支持email包。为此,email.Utils.formatdate()函数已更改为可用于替换rfc822.formatdate()您可能想编写新的电子邮件处理代码。(由Anthony Baxter执行。)

  • os模块添加了一个新的urandom(n)函数,返回一个包含n字节随机数据的字符串。此函数提供对平台特定的随机性源的访问,例如Linux上的/dev/urandom或Windows CryptoAPI。(由Trevor Perrin提供。)

  • 另一个新函数:os.path.lexists(path)在由path指定的文件存在时返回true,无论它是否为符号链接。这与现有的os.path.exists(path)函数不同,如果path是指向不存在的目标的符号链接,则返回false。(由Beni Cherniavsky提供)

  • os模块下面的posix模块添加了新的getsid()函数。(由J.Raynor。)

  • poplib模块现在支持基于SSL的POP。(由Hector Urtubia提供。)

  • profile模块现在可以配置C扩展功能。(由Nick Bastin提供)

  • random模块具有称为getrandbits(N)的新方法,其返回长整数N位。现有的randrange()方法现在在适当的情况下使用getrandbits(),使得生成任意大的随机数更加高效。(由Raymond Hettinger提供)

  • re模块接受的正则表达式语言用简单的条件表达式扩展,写为(?(group)A|B)是数字组ID或用表达式中较早的(?P<group>...)定义的组名称。如果指定的组匹配,则将针对字符串测试正则表达式模式A;如果组不匹配,则将使用模式B(供稿人:Gustavo Niemeyer。)

  • 由于Gustavo Niemeyer的大量工作,re模块也不再递归。在递归正则表达式引擎中,某些模式导致大量的C堆栈空间被消耗,并且可能溢出堆栈。例如,如果您将a字符的30000字节字符串与表达式(a|b)+匹配,则每个字符消耗一个堆栈帧。Python 2.3试图检查堆栈溢出并引发一个RuntimeError异常,但某些模式可能会阻止检查,如果你是不幸的Python可能segfault。Python 2.4的正则表达式引擎可以匹配这个模式没有问题。

  • signal模块现在对signal.signal()函数的参数执行更严格的错误检查。例如,您不能在SIGKILL信号上设置处理程序;以前的Python版本会静静地接受这个,但2.4会引发一个RuntimeError异常。

  • 两个新功能添加到socket模块。socketpair()返回一对连接的套接字,getservbyport(port)查找给定端口号的服务名称。(由Dave Cole和Barry Warsaw提供)

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

  • tarfile模块现在默认生成GNU格式的tar文件。(供稿人:LarsGustäbel。)

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

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

    其他线程可以为numberurl属性分配和检索自己的值。您可以子类化local以初始化属性或添加方法。(供稿人:Jim Fulton。)

  • timeit模块现在会在定时循环期间自动禁用周期性垃圾容器。这种变化使得连续的时间更可比。(由Raymond Hettinger提供)

  • weakref模块现在支持更多种类的对象,包括Python函数,类实例,集合,frozensets,deques,数组,文件,套接字和正则表达式模式对象。(由Raymond Hettinger提供)

  • xmlrpclib模块现在支持用于在单个HTTP操作中传输多个XML-RPC调用的多调用扩展。(由Brian Quinlan提供)

  • 已删除mpzrotorxreadlines模块。

cookielib

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已更改为与cookielib交互:HTTPCookieProcessor管理访问URL时使用的cookie jar。

该模块由John J. Lee提供。

doctest

由于Edward Loper和Tim Peters,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
**********************************************************************

Build and C API Changes

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

  • 添加了三个新的方便宏,用于扩展函数的公共返回值:Py_RETURN_NONEPy_RETURN_TRUEPy_RETURN_FALSE(由Brett Cannon提供。)
  • 另一个新宏Py_CLEAR(obj)减少obj的引用计数,并将obj设置为空指针。(供稿人:Jim Fulton。)
  • 新的函数PyTuple_Pack(N, obj1, obj2, ..., objN),从可变长度的Python对象参数列表构造元组。(由Raymond Hettinger提供)
  • 新的函数PyDict_Contains(d, k)实现快速的字典查找,而不掩蔽查找过程中产生的异常。(由Raymond Hettinger提供)
  • 如果Py_IS_NAN(X)宏的float或double参数X为NaN,则返回1。(由Tim Peters提供。)
  • C代码可以通过使用新的PyEval_ThreadsInitialized()函数来避免不必要的锁定,以告知是否执行了任何线程操作。如果此函数返回false,则不需要锁定操作。(由Nick Coghlan提供)
  • 新函数PyArg_VaParseTupleAndKeywords()PyArg_ParseTupleAndKeywords()相同,但采用va_list而不是多个参数。(由Greg Chapman提供)
  • 新方法标志METH_COEXISTS允许在slot中定义的函数与具有相同名称的PyCFunction共存。这可以将方法的访问时间减半,例如set.__contains__()(由Raymond Hettinger提供)
  • Python现在可以为解释器本身创建额外的分析,旨在帮助开发Python核心的人。提供--enable-profilingconfigure脚本将允许您使用gprof配置解释器,并提供--with-tsc开关可以使用Pentium的时间戳计数器寄存器进行性能分析。请注意,--with-tsc开关略有误称,因为分析功能也适用于PowerPC平台,尽管该处理器架构不会调用该寄存器“TSC寄存器”。(由Jeremy Hylton提供。)
  • tracebackobject类型已重命名为PyTracebackObject

Port-Specific Changes

  • Windows端口现在构建在MSVC ++ 7.1以及版本6下。(供稿:Martin vonLöwis。)

Porting to Python 2.4

本部分列出了可能需要更改代码的上述更改:

  • 太大的左移位和十六进制/八进制常量不再触发FutureWarning并返回限制为32或64位的值;而是返回一个长整数。
  • 整数运算将不再触发OverflowWarning在Python 2.5中,OverflowWarning警告将消失。
  • zip()内建函数和itertools.izip()现在返回一个空列表,而不是在没有参数的情况下调用TypeError
  • 您无法再比较由datetime模块提供的datedatetime实例。Two instances of different classes will now always be unequal, and relative comparisons (<, >) will raise a TypeError.
  • dircache.listdir()现在将异常传递给调用者,而不是返回空列表。
  • LexicalHandler.startDTD()用于以错误的顺序接收公共ID和系统ID。这已经更正;依赖于错误顺序的应用程序需要修复。
  • fcntl.ioctl()现在警告mutate参数是否被省略和相关。
  • tarfile模块现在默认生成GNU格式的tar文件。
  • 在导入模块时遇到故障不再在sys.modules中留下部分初始化的模块对象。
  • None现在是常数;将新值绑定到名称None的代码现在是语法错误。
  • signals.signal()函数现在引发某些非法值的RuntimeError异常;以前这些错误会默默通过。例如,您不能再在SIGKILL信号上设置处理程序。

Acknowledgements

作者感谢以下人员为本文的各种草案提供建议,更正和协助:Koray Can,Hye-Shik Chang,Michael Dyck,Raymond Hettinger,Brian Hurt,Hamish Lawson,Fredrik Lundh,Sean Reifschneider,Sadruddin Rejeb。