python 3.1的新功能

作者

雷蒙德·赫廷格

本文解释了与3.0相比,python 3.1中的新特性。

PEP 372:订购字典

常规的python字典以任意顺序迭代键/值对。多年来,许多作者编写了一些替代实现,它们记住了密钥最初插入的顺序。基于这些实现的经验,新的 collections.OrderedDict 已经介绍了类。

ordereddict API基本上与常规字典相同,但将按保证的顺序迭代键和值,具体顺序取决于首次插入键的时间。如果新条目覆盖现有条目,则原始插入位置保持不变。删除一个条目并重新插入它将移动到末尾。

标准库现在支持在几个模块中使用有序字典。这个 configparser 模块默认使用它们。这样可以读取、修改配置文件,然后按原始顺序将其写回。这个 _asdict() 方法 collections.namedtuple() 现在返回一个有序字典,其值的显示顺序与基础元组索引的显示顺序相同。这个 json 正在用一个 object_pairs_hook 允许解码器生成orderedticts。还增加了对第三方工具的支持,如 PyYAML .

参见

PEP 372 -有序词典

佩普由阿敏·罗纳彻和雷蒙德·赫廷格写。由Raymond Hettinger编写的实现。

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'

支持的类型是 intfloatcomplexdecimal.Decimal .

关于如何指定点、空格、撇号或下划线等可选分隔符的讨论正在进行中。支持区域设置的应用程序应使用现有的 n 格式说明符,它已经支持数千个分隔符。

参见

PEP 378 -千位分隔符的格式说明符

Pep由Raymond Hettinger编写,Eric Smith和Mark Dickinson实施。

其他语言更改

对核心python语言所做的一些较小的更改是:

  • 包含 __main__.py 现在可以通过将文件名传递给解释器来直接执行文件。目录/zipfile将自动作为sys.path中的第一个条目插入。(安迪楚的建议和初始补丁;菲利普·J·埃比和尼克·科格伦的修订补丁; bpo-1739468

  • 这个 int() 获得A型 bit_length 返回用二进制表示其参数所需的位数的方法:

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

    (由弗雷德里克·约翰森、维克多·斯廷纳、雷蒙德·赫廷格和马克·狄金森撰稿; bpo-3439

  • 中的字段 format() 字符串现在可以自动编号:

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

    以前,字符串需要带编号的字段,例如: 'Sir {{0}} of {{1}}' .

    (由埃里克·史密斯提供; bpo-5237

  • 这个 string.maketrans() 函数已被弃用,并被新的静态方法替换, bytes.maketrans()bytearray.maketrans() . 此更改解决了关于哪些类型由 string 模块。现在, strbytesbytearray 每个人都有自己的 美孚公司翻译 方法使用适当类型的中间翻译表。

    (由乔治布兰德尔提供; bpo-5675

  • 的语法 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
    

    (马克·狄金森撰稿; 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协议通过使用旧算法确保跨平台的可移植性。

    (埃里克·史密斯和马克·狄金森撰稿; bpo-1580

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

  • 增加了一个 collections.Counter 类以支持方便地对序列中的唯一项或iterable进行计数:

    >>> 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.GzipFilebz2.BZ2File 类现在支持上下文管理协议:

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

    (安托万·皮特鲁供稿)

  • 这个 decimal 模块现在支持从二进制文件创建十进制对象的方法 float . 转换是精确的,但有时会令人惊讶:

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

    长十进制结果显示存储的实际二进制分数 1.1 . 分数有很多位数,因为 1.1 不能用二进制精确表示。

    (由Raymond Hettinger和Mark Dickinson提供。)

  • 这个 itertools 模块增加了两个新功能。这个 itertools.combinations_with_replacement() 函数是生成置换和笛卡尔积等四种组合数学的函数之一。这个 itertools.compress() 函数从apl模仿其同名。此外,现有的 itertools.count() 函数现在有一个可选的 step 并且可以接受任何类型的计数序列,包括 fractions.Fractiondecimal.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() 现在支持关键字参数 重命名 它允许无效的字段名自动转换为形式为_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() 函数现在接受一个标志参数。

    (格雷戈里·史密斯供稿)

  • 这个 logging 模块现在实现一个简单的 logging.NullHandler 类,用于不使用日志记录但调用库代码的应用程序。设置空处理程序将禁止虚假警告,例如“无法为记录器foo找到任何处理程序”::

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

    (由Vinay Sajip提供; bpo-4384

  • 这个 runpy 支持 -m 命令行开关现在通过查找和执行 __main__ 提供包名称时的子模块。

    (由安迪·瓦伊达提供; bpo-4195

  • 这个 pdb 模块现在可以访问和显示通过 zipimport (或任何其他符合 PEP 302 加载器)。

    (由亚历山大·伯罗波尔斯基提供; bpo-4201

  • functools.partial 现在可以对对象进行酸洗。

(安托万·皮特鲁和杰西·诺勒建议。由Jack Diederich实施; bpo-5228

  • 添加 pydoc 符号的帮助主题,以便 help('@') 在交互环境中按预期工作。

    (大卫·拉班供稿) bpo-4739

  • 这个 unittest 模块现在支持跳过单个测试或测试类。它支持将测试标记为预期失败,即已知已破坏的测试,但不应将其视为测试结果的失败:

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

    (本杰明·彼得森和安托万·皮特鲁撰稿)

  • 这个 io 模块有三个新的常量 seek() 方法 SEEK_SETSEEK_CURSEEK_END .

  • 这个 sys.version_info tuple现在是一个命名tuple::

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

    (由罗斯·莱特提供; bpo-4285

  • 这个 nntplibimaplib 模块现在支持IPv6。

    (由Derek Morr提供; bpo-1655bpo-1664

  • 这个 pickle 当与协议2或更低版本一起使用时,模块已经被调整为与python 2.x更好的互操作性。标准库的重组改变了许多对象的形式引用。例如, __builtin__.set 在python中,2被称为 builtins.set 在python 3中。这一变化使在不同版本的python之间共享数据的工作陷入混乱。但现在,当选择协议2或更低版本时,pickler将自动使用旧的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实现之间迁移数据时,应该使用最新的pickle协议(协议3),因为它不试图与python 2.x保持兼容。

    (由Alexandre Vassalotti和Antoine Pitrou提供, bpo-6137

  • 一个新的模块, importlib 已添加。它提供了一个完整的、可移植的、纯Python引用实现 import 声明及其副本 __import__() 功能。它代表着在记录和定义输入期间发生的行动方面向前迈出了实质性的一步。

    (布雷特·坎农供稿)

优化

增加了主要的性能增强:

  • 新的I/O库(定义见 PEP 3116 )大部分是用Python编写的,很快就被证明是Python3.0中的一个有问题的瓶颈。在python 3.1中,I/O库已经完全用C语言重写,速度是现有任务的2到20倍。纯Python版本仍然可以通过 _pyio 模块。

    (由Amaury Forgot d'Arc和Antoine Pitrou提供。)

  • 添加了一个启发式的,这样垃圾收集器就不会跟踪只包含不可跟踪对象的元组和dict。这可以减少收集的大小,从而减少长时间运行的程序的垃圾收集开销,这取决于它们对数据类型的特殊使用。

    (由Antoine Pitrou提供, bpo-4688

  • 启用名为的配置选项 --with-computed-gotos 在支持它的编译器(特别是:gcc、sunpro、icc)上,字节码评估循环使用一种新的调度机制进行编译,根据系统、编译器和基准,该机制可以提高20%的速度。

    (由Antoine Pitrou和其他一些参与者共同提供, bpo-4753

  • UTF-8、UTF-16和Latin-1的解码速度现在快了两到四倍。

    (由Antoine Pitrou和Amaury Forgot d'Arc提供, bpo-4868

  • 这个 json 模块现在有一个C扩展,可以大大提高其性能。此外,对API进行了修改,以便JSON只与 str 没有 bytes .这一变化使模块与 JSON specification 它是用Unicode定义的。

    (由Bob Ipolito提供,由Antoine Pitrou和Benjamin Peterson转换为PY3.1; bpo-4136

  • unpickling现在会实习生pickled对象的属性名。这样可以节省内存并使pickle变小。

    (由Jake McGuire和Antoine Pitrou提供; bpo-5084

IDLE

  • idle的格式菜单现在提供了一个选项,可以从源文件中删除尾随空格。

    (由罗杰·D·塞尔维提供; bpo-5150

构建和C API更改

对python构建过程和C API的更改包括:

  • 整数现在存储在基2中的内部 15或2进制 30,基础在构建时确定。以前,它们总是存储在基2中 15。使用基2 30在64位机器上提供了显著的性能改进,但是32位机器上的基准测试结果是混合的。因此,默认值是使用基2 30 on 64-bit machines and base 2 15在32位机器上;在UNIX上,有一个新的配置选项 --enable-big-digits 可用于覆盖此默认值。

    除了性能改进之外,最终用户应该看不到这个更改,但有一个例外:为了测试和调试的目的,有一个新的 sys.int_info 它提供有关内部格式的信息,给出每个数字的位数和用于存储每个数字的C类型的字节大小:

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

    (马克·狄金森撰稿; bpo-4258

  • 这个 PyLong_AsUnsignedLongLong() 函数现在处理一个负数 派龙 通过提高 OverflowError 而不是 TypeError .

    (由马克·狄金森和莉桑德罗·达尔克林撰稿; bpo-5175

  • 已弃用 PyNumber_Int() . 使用 PyNumber_Long() 相反。

    (马克·狄金森撰稿; bpo-4910

  • 增加了一个新的 PyOS_string_to_double() 用于替换已弃用函数的函数 PyOS_ascii_strtod()PyOS_ascii_atof() .

    (马克·狄金森撰稿; bpo-5914

  • 补充 PyCapsule 作为替代 PyCObject 应用程序编程接口。主要区别在于,新类型有一个定义良好的接口,用于传递类型安全信息,还有一个不太复杂的签名,用于调用析构函数。旧类型具有有问题的API,现在已弃用。

    (拉里·黑斯廷斯撰稿; 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
    **********************************************************************
    
  • 协议2或更低版本的pickle模块中的自动名称重新映射会使python 3.1 pickle在python 3.0中无法读取。一种解决方案是使用协议3。另一个解决方案是设置 fix_imports 选择权 False . 有关详细信息,请参阅上面的讨论。