Python 2.4 新增Function

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

Python 2.4 是中等大小的版本。它没有引入与基本的 Python 2.2 一样多的更改,但是引入了比保守的 2.3 版本更多的Function。最重要的新语言Function是函数装饰器和生成器表达式。其他大多数更改是对标准库的更改。

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

本文不try提供每个新Function的完整规范,而是提供每个Function的简要介绍。有关完整的详细信息,您应该参考 Python 2.4 的文档,例如《 Python 库参考》和《 Python 参考手册》。通常,您会因特殊的新Function而被转到 PEP,以解释实现和设计原理。

PEP 218:内置集合对象

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

>>> 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类作为子类,则该模块可能很有用。当前没有计划弃用该模块。

See also

  • PEP 218-添加内置 Set 对象类型

  • 最初由格雷格·威尔逊(Greg Wilson)提出,finally由雷蒙德·海廷格(Raymond Hettinger)实施。

PEP 237:统一长整数和整数

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

有问题的表达式主要是左移以及冗长的十六进制和八进制常数。例如,2 << 32在 2.3 中产生警告,在 32 位平台上评估为 0.在 Python 2.4 中,此表达式现在返回正确的答案 8589934592.

See also

  • PEP 237-统一长整数和整数

  • Moshe Zadka 和 GvR 撰写的原始 PEP。 2.4 的更改由 Kalle Svensson 实施。

PEP 289:生成器表达式

Python 2.2 和itertools模块中引入的迭代器Function使编写循环大型数据集的程序变得更加容易,而无需一次将整个数据集存储在内存中。列表理解不太适合这张图片,因为它们产生了一个包含所有项目的 Python 列表对象。这不可避免地将所有对象拉入内存,如果您的数据集非常大,则可能会出现问题。try编写Function样式的程序时,自然会写类似以下内容:

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

instead of

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 的 Future 版本将对此进行更改,从而使列表推导在此方面与生成器表达式匹配。

See also

  • PEP 289-生成器表达式

  • 由 Raymond Hettinger 提出,由 Jiwon Seo 实施,并在 Hye-Shik Chang 的早期努力下实施。

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

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

按名称替换变量的常用方法是%运算符:

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

编写模板字符串时,很容易忘记右括号后的is。如果模板位于 Python 模块中,那么这不是一个大问题,因为您可以运行代码,获取“不受支持的格式字符” ValueError并解决问题。但是,请考虑使用 Mailman 之类的应用程序,其中的模板字符串或翻译由不了解 Python 语言的用户编辑。格式字符串的语法很难向此类用户解释,并且如果他们 Importing 有误,则很难向他们提供有用的反馈。

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'

See also

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

  • 由 Barry Warsaw 编写并实施。

PEP 318:函数和方法的装饰器

Python 2.2 pass添加静态方法和类方法扩展了 Python 的对象模型,但并未扩展 Python 的语法以提供定义静态或类方法的任何新方法。相反,您必须以通常的方式编写def语句,然后将结果方法传递给staticmethod()classmethod()函数,该函数会将函数包装为新类型的方法。您的代码如下所示:

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

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

如果该方法很长,很容易会遗漏或忘记函数主体之后的classmethod()调用。

目的始终是添加一些语法以使此类定义更具可读性,但是在 2.2 发行之时,良好的语法并不明显。如今,仍然的语法仍然不明显,但用户要求更轻松地访问该Function。已添加新的语法Function来满足此需求。

新Function称为“Function装饰器”。该名称来源于classmethod()staticmethod()和朋友在Function对象上存储其他信息的想法。他们正在装饰具有更多细节的Function。

该符号来自 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属性可写。此属性用于在回溯中显示函数名称,因此装饰器应更改所构造和返回的任何新函数的名称。

See also

  • PEP 318-函数,方法和类的装饰器

  • 由 Kevin D. Smith,Jim Jewett 和 Skip Montanaro 撰写。有几个人编写了实现Function装饰器的补丁,但实际上检入的是由 Mark Russell 编写的补丁#979728.

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

  • 该 Wiki 页面包含几个装饰器示例。

PEP 322:反向迭代

一个新的内置函数reversed(seq)接受一个序列,并返回一个迭代器,该迭代器以相反的 Sequences 遍历序列的元素。

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

See also

  • PEP 322-反向迭代

  • 由 Raymond Hettinger 撰写和实施。

PEP 324:新的子流程模块

标准库提供了多种执行子流程的方式,提供了不同的Function和不同的复杂性级别。 os.system(command)易于使用,但速度较慢(它运行一个执行命令的 shell 进程),并且很危险(您必须谨慎转义 shell 的元字符)。 popen2模块提供的类可以捕获子流程中的标准输出和标准错误,但是命名令人困惑。 subprocess模块将其清理干净,提供了一个统一的界面,该界面提供了您可能需要的所有Function。

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

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

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

创建Popen实例后,可以调用其wait()方法暂停直到子进程退出,poll()检查是否退出而没有暂停,或communicate(data)将字符串* data *发送到子进程的标准 Importing。 communicate(data)然后读取子进程已发送到其标准输出或标准错误的任何数据,并返回 Tuples(stdout_data, stderr_data)

call()是一种快捷方式,它将其参数传递给Popen构造函数,await 命令完成,然后返回子进程的状态代码。它可以用作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 的这一部分。

See also

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

  • 由 PeterÅstrand 在 Fredrik Lundh 和其他人的协助下编写和实施。

PEP 327:十进制数据类型

Python 始终支持基于底层 C double类型的浮点(FP)数字作为数据类型。但是,尽管大多数编程语言都提供浮点类型,但许多人(甚至是程序员)都没有意识到浮点数不能准确表示某些小数部分。新的Decimal类型可以准确地表示这些分数,直到用户指定的精度极限。

为什么需要十进制?

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

例如,数字 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

打印数字时,错误并不总是显而易见的,因为 C 库提供了 FP 到十进制字符串的转换,并且大多数 C 库都试图产生有意义的输出。即使未显示,仍然存在不准确之处,后续操作可能会放大错误。

对于许多应用程序,这并不重要。如果要绘制点并将其显示在监视器上,则 1.1 和 1.1000000000000001 之间的差异太小而看不到。报表通常会将输出限制为一定的小数位数,如果将数字四舍五入为两个或三个甚至八个小数位,则错误永远不会出现。但是,对于确实重要的应用程序,要实现自己的自定义算术例程需要进行大量工作。

因此,创建了Decimal类型。

小数类型

新模块decimal已添加到 Python 的标准库中。它包含两个类DecimalContextDecimal实例代表数字,而Context实例用于包装各种设置,例如精度和默认舍入模式。

Decimal实例是不可变的,例如常规的 Python 整数和 FP 数字;创建完成后,您将无法更改实例表示的值。 Decimal实例可以由整数或字符串创建:

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

您还可以提供包含符号的 Tuples,以十进制数字的 Tuples 表示的尾数以及指数:

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

警告:符号位是布尔值,因此 0 为正,1 为负。

从浮点数转换会带来一个问题:代表 1.1 的 FP 数是否应该准确地转换为十进制数,或者精确到 1.1 或十进制加上任何引入的误差?决定是回避问题,并将这种转换排除在 API 之外。相反,您应该使用所需的精度将浮点数转换为字符串,并将该字符串传递给Decimal构造函数:

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

拥有Decimal个实例后,您可以对它们执行常规的 math 运算。一个限制:求幂需要一个整数指数:

>>> 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,但是如果需要其他Function(例如三角函数),则必须实现它们。

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

上下文类型

Context类的实例封装了几种用于十进制运算的设置:

可以pass调用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")

错误条件的默认操作是可选的;模块可以返回一个特殊值,例如 infinity 或 not-a-number,也可以引发异常:

>>> 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模块的文档,其中包括快速入门教程和参考。

See also

  • 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:多行导入

一种语言更改是一种小的语法调整,旨在使从模块中导入许多名称变得更加容易。在from module import names语句中,* 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 的这一部分尚未针对 Python 2.4 实现,但已针对 Python 2.5 完成。

See also

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

  • 由 Aahz 撰写。多行导入由 Dima Dorfman 实施。

PEP 331:与语言环境无关的浮点/字符串转换

locale模块可让 Python 软件选择各种转换和显示约定,这些约定和显示约定仅限于特定国家或 locale 或语言。但是,该模块非常小心,不要更改数字语言环境,因为 Python 实现中的各种Function都要求数字语言环境保持设置为'C'语言环境。通常是因为代码使用的是 C 库的atof()函数。

但是,未设置数字语言环境会给使用第三方 C 库的扩展带来麻烦,因为它们没有正确的语言环境设置。激励性的示例是 GTK,其用户界面小部件未在当前语言环境中显示数字。

PEP 中描述的解决方案是在 Python API 中添加三个新Function,以执行仅 ASCII 转换,而忽略区域设置:

这些函数的代码来自 GLib 库(https://developer.gnome.org/glib/stable/),该库的开发人员友好地重新许可了相关Function并将其捐赠给 Python Software Foundation。现在,locale模块可以更改数字语言环境,从而使 extensions(例如 GTK)产生正确的结果。

See also

  • PEP 331-与语言环境无关的浮点/字符串转换

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

其他语言更改

以下是 Python 2.4 对核心 Python 语言所做的所有更改。

>>> 'www.python.org'.split('.', 1)
['www', 'python.org']
'www.python.org'.rsplit('.', 1)
['www.python', 'org']

对于* cmp *参数,该值应该是一个比较函数,该函数接受两个参数并根据参数的比较方式返回-1、0 或 1.然后将使用此Function对列表进行排序。以前,这是可以提供给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 参数的示例是执行不区分大小写排序的旧方法。它可以工作,但比使用 key 参数要慢。使用 key 对列表中的每个元素调用一次lower()方法,而使用 cmp 将对每个比较调用两次,因此,使用 key *可以节省lower()方法的调用。

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

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

最后,* reverse *参数采用布尔值。如果值为 true,则列表将按相反 Sequences 排序。现在您可以写L.sort(reverse=True)来代替L.sort(); L.reverse()

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

(对sort()的所有更改均由 Raymond Hettinger 提供.)

>>> 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 提供.)

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

(由 Raymond Hettinger 提供.)

Optimizations

2.4 优化的finally结果是,Python 2.4 运行 pystone 基准比 Python 2.3 快 5%,比 Python 2.2 快 35%。 (pystone 不是一个特别好的基准,但是它是最常用的 Python 性能度量.您自己的应用程序可能会从 Python 2.4 中获得或多或少的好处.)

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

像往常一样,Python 的标准库获得了许多增强Function和错误修复。这是最值得注意的更改的部分列表,按模块名称的字母 Sequences 排列。请查阅源代码树中的Misc/NEWS文件以获得更完整的更改列表,或查看 CVS 日志以获取所有详细信息。

>>> 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 提供.)

这是一个使这一点更清楚的例子。 * 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()通常与已排序的 Importing 一起使用。 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)]

(由张慧植提供.)

>>> 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()必须保留迭代器返回的值的副本;在最坏的情况下,可能需要保留所有这些。因此,如果前导迭代器在长 Importing 流中可以远远领先于尾随迭代器,则应谨慎使用。如果间隔很大,则最好使用list()代替。当迭代器彼此密切跟踪时,tee()是理想的。可能的应用程序包括书签,窗口或超前迭代器。 (由 Raymond Hettinger 提供.)

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

logging软件包的其他新增Function包括log(level, msg)便捷方法以及TimedRotatingFileHandler类,该类按一定时间间隔旋转其日志文件。该模块已经具有RotatingFileHandler,一旦文件超过一定大小,它将旋转日志。这两个类都派生自新的BaseRotatingHandler类,该类可用于实现其他旋转处理程序。

(由 Vinay Sajip 实施的更改.)

>>> 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 提供.)

import threading

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

其他线程可以为numberurl属性分配和检索自己的值。您可以将local子类化以初始化属性或添加方法。 (由吉姆·富尔顿贡献.)

cookielib

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

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

urllib2已更改为与cookielib交互:HTTPCookieProcessorManagement 访问 URL 时使用的 cookie jar。

该模块由 John J. Lee 提供。

doctest

感谢 Edward Loper 和 Tim Peters,对doctest模块进行了大量的重构。测试仍然可以像运行doctest.testmod()一样简单,但是重构允许以各种方式自定义模块的操作

新的DocTestFinder类从给定对象的文档字符串中提取测试:

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的全新子类。

默认的输出检查器提供了许多方便的Function。例如,使用doctest.ELLIPSIS选项标志,预期输出中的Ellipsis号(...)会与任何子字符串匹配,从而更容易容纳以较小方式变化的输出:

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

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

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

另一个新Function是pass指定doctest.REPORT_UDIFF(统一差异),doctest.REPORT_CDIFF(上下文差异)或doctest.REPORT_NDIFF(增量风格)选项标志来产生输出的差异样式显示。例如:

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的情况下运行上述Function的测试,您将获得以下输出:

**********************************************************************
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 和 C API 的更改

对 Python 的生成过程和 C API 的一些更改包括:

Port-Specific Changes

移植到 Python 2.4

本部分列出了先前描述的更改,可能需要更改您的代码:

Acknowledgements

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

首页