Python 3.1 有什么新�化¶

作者:

Raymond Hettinger(译者:wh2099 at outlook dot com)

本文介�了 Python 3.1 相比 3.0 的新特性。 Python 3.1 �布于 2009 年 6 月 27 日。

PEP 372: 有�字典¶

常规的 Python 字典会以任�顺�迭代键/值对。 多年以�,有好几�作者编写了�以记�键的�始�入顺�的替代实现。 基于这些实现的�验,现在引入了新的 collections.OrderedDict 类。

OrderedDict API 与常规字典基本相�,但将根��个键首次�入的时间以有��的顺��迭代键和值。 如果一个新�目覆盖了现有的�目,则原始�入�置会����。 删除�目并�新�入则会将其移至末尾。

标准库现在支�在�些模�中使用有�字典。 configparser 模�会默认使用它们。 这使得�置文件将以其原始顺�被读��修改和�新写入。 collections.namedtuple() 的 _asdict() 方法现在会返回一个值的出现顺�与下层的元组索引�相�的有�字典。 json 模�已使用 object_pairs_hook �构建以�许由解�器生�有�字典。 还添加了对第三方工具的支�如 PyYAML。

��

PEP 372 - 有�字典

PEP 由 Armin Ronacher 和 Raymond Hettinger 撰写,由 Raymond Hettinger 实现。

因为一个有�字典记�它的顺�,他�以用于连接排�字典

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

当�目删除时,新的排�字典会维护它的顺�。但如果有新的�目添加进�,键就被加入到末端,顺�就��维护。

PEP 378: ��分隔符的格�说明符¶

内置的 format() 函数和 str.format() 方法使用的迷你语言现在包括一�以��分隔符格�化数字的简����感知语言区域的方�。 这�供了更为人性化的程�输出,��了外观专业程度与�读性:

>>> format(1234567, ',d')
'1,234,567'
>>> format(1234567.89, ',.2f')
'1,234,567.89'
>>> format(12345.6 + 8901234.12j, ',f')
'12,345.600000+8,901,234.120000j'
>>> format(Decimal('1234567.89'), ',f')
'1,234,567.89'

支�的类型有 int, float, complex 和 decimal.Decimal。

目�还在讨论�如何指定替代分隔符如点��空格�撇�或下划线等。 �感知语言区域的应用程�应当使用现有的支���分隔符的 n 格�说明符。

��

PEP 378 - ��分隔符的格�说明符

PEP 由 Raymond Hettinger 撰写,并由 Eric Smith 和 Mark Dickinson 实现

其他语言特性修改¶

对Python 语言核心进行的�改动:

  • 包括 __main__.py 文件的目录和 zip 归档文件现在å�¯é€šè¿‡å°†å…¶å��称传给解释器æ�¥ç›´æŽ¥æ‰§è¡Œã€‚ 这样的目录/zip 文件会自动作为 sys.path 的第一个æ�¡ç›®æ�’入。 (由 Andy Chu æ��议并编写åˆ�å§‹è¡¥ä¸�;由 Phillip J. Eby å’Œ Nick Coghlan 改进补ä¸�ï¼›bpo-1739468。)

  • int() 类型增加了一个 bit_length 方法用æ�¥è¿”回以二进制代表其å�‚数值所需的比特ä½�æ•°é‡�:

    >>> n = 37
    >>> bin(37)
    '0b100101'
    >>> n.bit_length()
    6
    >>> n = 2**123-1
    >>> n.bit_length()
    123
    >>> (n+1).bit_length()
    124
    

    (由 Fredrik Johansson, Victor Stinner, Raymond Hettinger 和 Mark Dickinson 在 bpo-3439 中贡献。)

  • format() 字符串中的字段现在å�¯è¢«è‡ªåŠ¨ç¼–å�·:

    >>> 'Sir {} of {}'.format('Gallahad', 'Camelot')
    'Sir Gallahad of Camelot'
    

    之�,字符串应当具有所需的编�字段例如: 'Sir {0} of {1}'。

    (由 Eric Smith在 bpo-5237 中贡献)

  • string.maketrans() 函数已被弃用并由新的é�™æ€�方法 bytes.maketrans() å’Œ bytearray.maketrans() 所å�–代。 这项更改解决了对于 string 模å�—所支æŒ�的类型的困惑。 现在,str, bytes å’Œ bytearray 分别拥有它们自己的具有适当类型的中间转译表的 maketrans å’Œ translate 方法。

    (由Georg Brandl在 bpo-5675 中贡献)

  • The syntax of the with 语å�¥çš„语法现在å…�许å�•个语å�¥ä¸­å­˜åœ¨å¤šä¸ªä¸Šä¸‹æ–‡ç®¡ç�†å™¨:

    >>> with open('mylog.txt') as infile, open('a.out', 'w') as outfile:
    ...     for line in infile:
    ...         if '<critical>' in line:
    ...             outfile.write(line)
    

    有了这个新语法,contextlib.nested() 函数已��必�因而现在已被弃用。

    (由 Georg Brandl 和 Mattias Brändström 贡献; appspot issue 53094。)

  • 现在 round(x, n) 当 x 为整数时将返回整数。 之å‰�是返回浮点数:

    >>> round(1123, -2)
    1100
    

    (由 Mark Dickinson在 bpo-4707 贡献)

  • Python 现在使用 David Gay 的算法æ�¥æŸ¥æ‰¾ä¸�会改å�˜å®žé™…值的最短浮点表示形å¼�。 这应当有助于缓解æŸ�些对于二进制浮点数的困惑。

    这项改进的优点对于 1.1 这样无法用二进制浮点精确表示的数�说是很明显的。 由于没有完全等价的表示,float('1.1') 这样的表达�会被求解为最接近的�表示值��六进制的 0x1.199999999999ap+0 或�进制的 1.100000000000000088817841970012523233890533447265625。 这个最接近的值过去和现在�然会在�续的浮点�算中被使用。

    新的改�针对的是如何显示数字。 在之�,Python 使用了一�简�的方�。 repr(1.1) 的值会被计算为 format(1.1, '.17g') 并将被求解为 '1.1000000000000001'。 使用 17 个数�的优点是它将凭借 IEEE-754 标准�确� eval(repr(1.1)) 将�好被�入到其原始值。 缺点则是会让许多人感觉这样的输出令人困惑(将二进制浮点表示形�的内在局�性误认为是 Python 本身的问题)。

    用于 repr(1.1) 的新算法更为智能并将返回 '1.1'。 在实际上,它会�索所有等价的字符串表示形�(使用相�的下层浮点值进行排�)并返回其中最短的表示形�。

    新算法倾�于尽�能放出更为清晰的表示形�,但它并�改�下层的值。 因此�然会是 1.1 + 2.2 != 3.3 虽然从表示形�上看情况�是这样。

    这个新算法�赖于下层浮点实现的�些特性。 如果未找到所需的特性,则将继续使用旧算法。 此外,文本 pickle �议也会通过使用旧算法���跨平�的�移�性。

    (由 Eric Smith 和 Mark Dickinson 在 bpo-1580 贡献)

新增,改进和弃用的模�¶

  • 增加了一个 collections.Counter 类以支æŒ�方便地统计一个åº�列或å�¯è¿­ä»£å¯¹è±¡ä¸­çš„唯一æ�¡ç›®æ•°é‡�。:

    >>> Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
    Counter({'blue': 3, 'red': 2, 'green': 1})
    

    (由 Raymond Hettinger 在 bpo-1696199 中贡献。)

  • å�Šåœ†äº†ä¸€ä¸ªæ–°æ¨¡å�— tkinter.ttk 用于访问带主题的 Tk 部件集。 ttk 的基本设计æ€�路,就是尽å�¯èƒ½åœ°æŠŠå®žçŽ°éƒ¨ä»¶è¡Œä¸ºçš„ä»£ç �与实现其外观的代ç �分离开æ�¥ã€‚

    (由 Guilherme Polo 在 bpo-2983 中贡献。)

  • gzip.GzipFile å’Œ bz2.BZ2File 类现在已支æŒ�上下文管ç�†å��è®®:

    >>> # Automatically close file after writing
    >>> with gzip.GzipFile(filename, "wb") as f:
    ...     f.write(b"xxx")
    

    (由 Antoine Pitrou 贡献。)

  • decimal 模å�—现在支æŒ�基于一个二进制 float æ�¥åˆ›å»º decimal 对象。 转æ�¢æ˜¯å‡†ç¡®çš„但有时也会令人å�ƒæƒŠ:

    >>> Decimal.from_float(1.1)
    Decimal('1.100000000000000088817841970012523233890533447265625')
    

    这个长长的 decimal 结果值显示了 1.1 所�存的实际二进制分数。 这个分数有许多�因为 1.1 无法用二进制�精确表示。

    (由Raymond Hettinger 和 Mark Dickinson贡献。)

  • itertools 模å�—增加了两个新函数。 itertools.combinations_with_replacement() 函数是生æˆ�组å�ˆæ•°å­¦ç»“果包括排列与笛å�¡å°”积的四个函数之一。 itertools.compress() 函数模仿了 APL 中的å�Œå��函数。 此外,现有的 itertools.count() 函数现在有一个å�¯é€‰çš„ step å�‚æ•°å¹¶å�¯æŽ¥å�—ä»»æ„�类型的计数åº�列包括 fractions.Fraction å’Œ decimal.Decimal:

    >>> [p+q for p,q in combinations_with_replacement('LOVE', 2)]
    ['LL', 'LO', 'LV', 'LE', 'OO', 'OV', 'OE', 'VV', 'VE', 'EE']
    
    >>> list(compress(data=range(10), selectors=[0,0,1,1,0,1,0,1,0,0]))
    [2, 3, 5, 7]
    
    >>> c = count(start=Fraction(1,2), step=Fraction(1,6))
    >>> [next(c), next(c), next(c), next(c)]
    [Fraction(1, 2), Fraction(2, 3), Fraction(5, 6), Fraction(1, 1)]
    

    (由 Raymond Hettinger 贡献。)

  • collections.namedtuple() 现在支æŒ�关键字å�‚æ•° rename,它å…�许将无效的字段å��自动转æ�¢ä¸º _0, _1 等形å¼�çš„ä½�ç½®å��称。 这在字段å��是由外部æº�如 CSV 标头ã€�SQL 字段列表或用户输入创建的时候会很有用处:

    >>> query = input()
    SELECT region, dept, count(*) FROM main GROUPBY region, dept
    
    >>> cursor.execute(query)
    >>> query_fields = [desc[0] for desc in cursor.description]
    >>> UserQuery = namedtuple('UserQuery', query_fields, rename=True)
    >>> pprint.pprint([UserQuery(*row) for row in cursor])
    [UserQuery(region='South', dept='Shipping', _2=185),
     UserQuery(region='North', dept='Accounting', _2=37),
     UserQuery(region='West', dept='Sales', _2=419)]
    

    (由 Raymond Hettinger 在 bpo-1818 中贡献。)

  • re.sub(), re.subn() å’Œ re.split() 函数现在å�¯æŽ¥å�—一个 flags å½¢å�‚。

    (由 Gregory Smith 贡献)

  • logging 模å�—现在为ä¸�使用 logging 但是调用了使用它的库代ç �的应用程åº�实现了一个简å�•çš„ logging.NullHandler 类。 设置一个空处ç�†å�¥æŸ„将会å±�蔽诸如 "找ä¸�到日志记录器 foo 的处ç�†å�¥æŸ„" 这样的虚å�‡è­¦å‘Š:

    >>> h = logging.NullHandler()
    >>> logging.getLogger("foo").addHandler(h)
    

    (由 Vinay Sajip 在 bpo-4384 中贡献。)

  • 支æŒ� -m 命令行开关的 runpy 模å�—现在也支æŒ�当æ��供包å��称时通过查找并执行 __main__ å­�模å�—æ�¥æ‰§è¡ŒåŒ…。

    (由 Andi Vajda 在 bpo-4195 中贡献。)

  • pdb 模å�—现在å�¯ä»¥è®¿é—®å¹¶æ˜¾ç¤ºé€šè¿‡ zipimport (或其他符å�ˆè§„范的 PEP 302 加载器) 加载的æº�代ç �。

    (由 Alexander Belopolsky 在 bpo-4201 中贡献。)

  • functools.partial 对象现在å�¯ä»¥è¢«å°�存。

(由 Antoine Pitrou 和 Jesse Noller �议,由 Jack Diederich 实现; bpo-5228。)

  • 为符å�·å¢žåŠ  pydoc 帮助主题以使得在交互环境下 help('@') 能符å�ˆé¢„期的效果。

    (由 David Laban 在 bpo-4739 中贡献。)

  • unittest 模å�—现在支æŒ�跳过å�•个测试或测试类。 并且它还支æŒ�将一个测试标记为已预期会失败,å�³å·²ç»�知é�“ä¸�å�¯ç”¨ï¼Œä½†ä¸�应在 TestResult 上被计为一次失败:

    class TestGizmo(unittest.TestCase):
    
        @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
        def test_gizmo_on_windows(self):
            ...
    
        @unittest.expectedFailure
        def test_gimzo_without_required_library(self):
            ...
    

    此外,还创建了一些针对异常的测试以便与使用 with 语�的上下文管�器一起工作:

    def test_division_by_zero(self):
        with self.assertRaises(ZeroDivisionError):
            x / 0
    

    此外,还新增了一些断言方法包括 assertSetEqual(), assertDictEqual(), assertDictContainsSubset(), assertListEqual(), assertTupleEqual(), assertSequenceEqual(), assertRaisesRegexp(), assertIsNone() 和 assertIsNotNone()。

    (由Benjamin Peterson 和 Antoine Pitrou 贡献。)

  • io 模å�—新增了三个常é‡�用于 seek() 方法: SEEK_SET, SEEK_CUR å’Œ SEEK_END。

  • sys.version_info 元组现在是一个具å��元组:

    >>> sys.version_info
    sys.version_info(major=3, minor=1, micro=0, releaselevel='alpha', serial=2)
    

    (由 Ross Light 在 bpo-4285 中贡献。)

  • nntplib å’Œ imaplib 模å�—现在支æŒ� IPv6。

    (由 Derek Morr 在 bpo-1655 和 bpo-1664 中贡献。)

  • 当使用å��è®® 2 或更低的版本时,pickle 模å�—已被调适以获得与 Python 2.x 更好的互æ“�作性。 标准库的é‡�组改å�˜äº†å¯¹äºŽè®¸å¤šå¯¹è±¡çš„æ­£å¼�引用。 例如,Python 2 中的 __builtin__.set 在 Python 3 中称为 builtins.set。 这一改å�˜ä½¿å¾—在ä¸�å�Œç‰ˆæœ¬çš„ Python 之间共享数æ�®çš„努力陷入混乱。 但是现在当选择å��è®® 2 或更低的版本时,å°�存器将自动使用旧的 Python 2 å��称进行加载和转储。 这样的é‡�映射将默认å�¯ç”¨ä½†å�¯ä»¥é€šè¿‡ fix_imports 选项æ�¥ç¦�用:

    >>> s = {1, 2, 3}
    >>> pickle.dumps(s, protocol=0)
    b'c__builtin__\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.'
    >>> pickle.dumps(s, protocol=0, fix_imports=False)
    b'cbuiltins\nset\np0\n((lp1\nL1L\naL2L\naL3L\natp2\nRp3\n.'
    

    这项改�的一个�幸但无���的副作用是由 Python 3.1 所产生的�议 2 版本的 pickle 对象对于 Python 3.0 将��读。 当在 Python 3.x 实现之间�移数�时,应当使用最新的�议 3 版本的 pickle �议,因为它�会试图与 Python 2.x ��兼容。

    (由 Alexandre Vassalotti 和 Antoine Pitrou 在 bpo-6137 中贡献。)

  • 增加了一个新模å�— importlib。 它æ��供了针对 import 语å�¥å�Šå…¶å¯¹åº”物 __import__() 函数的完整ã€�å�¯ç§»æ¤�的纯 Python 引用实现。 它代表了在记录和定义导入期间所å�‘生的行动中实质性的一步。

    (由 Brett Cannon 贡献。)

性能优化¶

已增加的主�性能改善:

  • æ–°çš„ I/O 库(如 PEP 3116 所定义的)主è¦�是用 Python 编写并很快被è¯�明是 Python 3.0 中的一个问题瓶颈。 在 Python 3.1 中,I/O 库已完全用 C é‡�写并根æ�®å…·ä½“任务的ä¸�å�Œæœ‰ 2 到 20 å€�的速度æ��å�‡ã€‚ 纯 Python 版本ä»�ç„¶å�¯é€šè¿‡ _pyio 模å�—访问以用于实验性目的。

    (由 Amaury Forgeot d'Arc 和 Antoine Pitrou 贡献。)

  • 添加了一个å�¯å�‘å¼�的工具以使仅包å�«ä¸�å�¯è¿½è¸ªå¯¹è±¡çš„元组和字典ä¸�会被垃圾回收器所追踪。 è¿™å�¯ä»¥å‡�少收集数æ�®çš„大å°�从而å‡�å°‘é•¿æ—¶é—´è¿�行的程åº�的垃圾收集开销,具体å�–决于它们对类型类型的使用方å¼�。

    (由 Antoine Pitrou 在 bpo-4688 中贡献。)

  • 通过在å�—支æŒ�的编译器(主è¦�有: gcc, SunPro, icc)上å�¯ç”¨å��为 --with-computed-gotos çš„é…�置选项,字节ç �求值循环会使用新的分派机制进行编译,根æ�®ç³»ç»Ÿã€�编译器和基准测试工具的ä¸�å�Œï¼Œè¯¥æœºåˆ¶å�¯èŽ·å¾—è‡³å¤š 20% 的速度æ��å�‡ã€‚

    (由 Antoine Pitrou 以�其他一些�与者在 bpo-4753 中贡献。)

  • UTF-8, UTF-16 å’Œ LATIN-1 的解ç �速度现已æ��å�‡äº†äºŒè‡³å››å€�。

    (由 Antoine Pitrou 和 Amaury Forgeot d'Arc 在 bpo-4868 中贡献。)

  • json 模å�—现在有了一个å�¯æ˜¾è‘—æ��å�‡å…¶æ€§èƒ½çš„ C 扩展。 此外,还对 API 进行了修改以使 json å�ªé€‚用于 str,而ä¸�å†�适用于 bytes。 这一修改使得该模å�—能与基于 Unicode çš„ JSON 规范 紧密匹é…�。

    (由 Bob Ippolito 在 bpo-4136 中贡献。并由 Antoine Pitrou 和 Benjamin Peterson 转�为Py3.1)

  • è§£å°�æ“�作现在将固定已å°�存对象的属性å��称。 è¿™å�¯ä»¥èŠ‚çœ�内存并让å°�存对象å�˜å¾—æ›´å°�。

    (由 Jake McGuire 和 Antoine Pitrou 在 bpo-5084 中贡献。)

IDLE¶

  • IDLE 的格å¼�è�œå�•现在æ��供了一个从æº�文件中去除尾部空格的选项。

    (由 Roger D. Serwy 在 bpo-5150 中贡献。)

构建和 C API 的改�¶

针对 Python 构建过程和 C API 的改�包括:

  • 现在整数在内部是以 2**15 为基数或以 2**30 为基数æ�¥å­˜å‚¨çš„,这个基数会在构建时被确定。 在之å‰�版本中,它们总是以 2**15 为基数æ�¥å­˜å‚¨ã€‚ 在 64 ä½�机器上使用 2**30 为基数å�¯æ˜¾è‘—æ��å�‡æ€§èƒ½ï¼Œä½†åœ¨ 32 ä½�机器上的基准测试结果则好å��å�‚å�Šã€‚ 因此,默认会在 64 ä½�机器上使用 2**30 为基数而在 32 ä½�机器上使用 2**15 为基数;在 Unix 上,有一个新的é…�置选项 --enable-big-digits å�¯è¢«ç”¨äºŽè¦†ç›–此默认值。

    除了性能��之外这项改�对于最终用户�说应当是���的,�有一个例外:出于测试和调试目的有一个新的�供相关内部格�信�的 sys.int_info,它给出了�个数�对应的比特�数和用户存储�个数�的以字节数表示的 C 类型大�:

    >>> import sys
    >>> sys.int_info
    sys.int_info(bits_per_digit=30, sizeof_digit=4)
    

    (由 Mark Dickinson在 bpo-4258 贡献)

  • PyLong_AsUnsignedLongLong() 函数现在将通过引å�‘ OverflowError 而ä¸�是 TypeError æ�¥å¤„ç�†è´Ÿçš„ pylong。

    (由 Mark Dickinson 和 Lisandro Dalcrin 在 bpo-5175 中贡献。)

  • 已弃用 PyNumber_Int()。 请改用 PyNumber_Long()。

    (由 Mark Dickinson在 bpo-4910 贡献)

  • 新增了 PyOS_string_to_double() 函数以å�–代已弃用的函数 PyOS_ascii_strtod() å’Œ PyOS_ascii_atof()。

    (由 Mark Dickinson 在 bpo-5914 贡献)

  • 增加了 PyCapsule 作为 PyCObject API 的替代。 主è¦�区别在于新类型拥有一个定义良好的接å�£ç”¨æ�¥ä¼ é€’类型安全信æ�¯ä»¥å�Šä¸€ä¸ªè¾ƒä½Žå¤�æ�‚度的签å��用æ�¥è°ƒç”¨æž�构器。 旧类型的 API 存在问题且现已被弃用。

    (由 Larry Hastings 在 bpo-5630 中贡献。)

移�到 Python 3.1¶

本节列出了先��述的改�以��能需�修改你的代�的其他问题修正:

  • 新的浮点字符串表示形å¼�å�¯èƒ½ä¼šç ´å��现有的 doctest。 例如:

    def e():
        '''Compute the base of natural logarithms.
    
        >>> e()
        2.7182818284590451
    
        '''
        return sum(1/math.factorial(x) for x in reversed(range(30)))
    
    doctest.testmod()
    
    **********************************************************************
    Failed example:
        e()
    Expected:
        2.7182818284590451
    Got:
        2.718281828459045
    **********************************************************************
    
  • 在 pickle 模å�—中用于å��è®® 2 或更低版本的自动å��ç§°é‡�映射会使得 Python 3.1 çš„ pickle 在 Python 3.0 中无法读å�–。 一ç§�解决方案是使用å��è®® 3。 å�¦ä¸€ç§�解决方案是将 fix_imports 选项设为 False。 请å�‚阅上é�¢çš„讨论æ�¥äº†è§£æ›´å¤šç»†èŠ‚ã€‚