What’s New In Python 3.1

作者:Raymond Hettinger

本文介绍了Python 3.1中与3.0相比的新功能。

PEP 372: Ordered Dictionaries

正则Python字典按任意顺序对键/值对进行迭代。多年来,许多作者已经编写了另外的实现,记住键最初插入的顺序。基于这些实现的经验,已经引入了新的collections.OrderedDict类。

OrderedDict API与常规字典基本相同,但会根据键首次插入的时间以有保证的顺序对键和值进行迭代。如果新条目覆盖现有条目,则原始插入位置保持不变。删除条目并重新插入会将其移动到结束。

标准库现在支持在几个模块中使用有序字典。默认情况下,configparser模块使用它们。这样可以读取,修改配置文件,然后按原始顺序写回配置文件。collections.namedtuple()_asdict()方法现在返回一个有序字典,其值按照与基础元组索引相同的顺序出现。json模块正在使用object_pairs_hook构建,以允许由解码器构建OrderedDicts。还为PyYAML等第三方工具添加了支持。

也可以看看

PEP 372 - 有序字典
PEP由Armin Ronacher和Raymond Hetting撰写。实施由Raymond Hettinger写。

PEP 378: Format Specifier for Thousands Separator

内建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 Hetting撰写,由Eric Smith和Mark Dickinson执行。

Other Language Changes

核心Python语言的一些较小的更改是:

  • 包含__main__.py文件的目录和zip存档现在可以通过将其名称传递给解释器直接执行。目录/ zipfile作为sys.path中的第一个条目自动插入。(由Andy Chu提出的建议和初始补丁;由Phillip J.Eby和Nick Coghlan修订的补丁; 问题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提供; 问题3439。)

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

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

    Formerly, the string would have required numbered fields such as: 'Sir {0} of {1}'.

    (由Eric Smith提供; 第5237期。)

  • string.maketrans()函数已被弃用,并被新的静态方法bytes.maketrans()bytearray.maketrans()替代。此更改解决了string模块支持哪些类型的混乱。现在,strbytesbytearray每个都有自己的maketranstranslate具有适当类型的中间转换表的方法。

    (供稿:Georg Brandl; issue 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和MattiasBrändström提供; appspot问题53094。)

  • 如果x是整数,则round(x, n)以前它返回一个浮点:

    >>> round(1123, -2)
    1100
    

    (由Mark Dickinson提供; 第4707期。)

  • Python现在使用David Gay的算法来找到不改变其值的最短浮点表示。这应该有助于减轻一些围绕二进制浮点数的混乱。

    使用1.1这样的数字很容易看出其意义,它在二进制浮点中没有精确的等价物。由于没有精确的等价物,像float('1.1')这样的表达式计算为最接近的可表示值,即十六进制中的0x1.199999999999ap+01.100000000000000088817841970012523233890533447265625十进制。该最接近的值仍然用于后续浮点计算。

    什么是新的是如何显示数字。以前,Python使用了一种简单的方法。repr(1.1)的值被计算为格式(1.1, '。17g') '1.1000000000000001'使用17位数字的优点是,它依赖于IEEE-754保证,以确保eval(repr(1.1))将准确地往返它的原始值。缺点是很多人发现输出是混乱的(错误地将二进制浮点表示的内在限制作为Python本身的问题)。

    repr(1.1)的新算法更聪明,并返回'1.1'实际上,它搜索所有等效的字符串表示(以相同的底层浮点值存储的字符串表示),并返回最短的表示。

    新算法在可能时倾向于发射更清晰的表示,但它不改变基础值。因此,仍然是1.1 + 2.2 != t5>,即使表示可能建议不同。

    新算法取决于底层浮点实现中的某些特征。如果未找到所需的功能,则将继续使用旧算法。此外,文本pickle协议通过使用旧算法保证跨平台可移植性。

    (由Eric Smith和Mark Dickinson提供; 问题1580

New, Improved, and Deprecated Modules

  • 添加了collections.Counter类,以支持对序列或迭代中的唯一项进行方便计数:

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

    (由Raymond Hettinger提供; 问题1696199。)

  • 添加了一个新模块,tkinter.ttk用于访问Tk主题控件集。ttk的基本思想是尽可能地从实现其外观的代码中分离实现窗口小部件行为的代码。

    (Contributed by Guilherme Polo; issue 2983。)

  • gzip.GzipFilebz2.BZ2File类现在支持上下文管理协议:

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

    (由Antoine Pitrou提供)

  • 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()函数现在有一个可选的步骤参数,可以接受任何类型的计数序列,包括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,它允许无效的fieldnames自动转换为位置名称_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提供; 问题1818。)

  • re.sub()re.subn()re.split()现在接受flags参数。

    (由Gregory Smith提供)

  • logging模块现在为不使用日志但正在调用库代码的应用程序实现了一个简单的logging.NullHandler类。设置空处理程序将抑制虚假警告,例如“没有处理程序可以找到logger foo”:

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

    (Contributed by Vinay Sajip; issue 4384)。

  • 支持-m命令行开关的runpy模块现在支持通过查找并执行一个__main__子模块。

    (由Andi Vajda提供; 问题4195。)

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

    (由Alexander Belopolsky提供; 第4201期。)

  • functools.partial对象现在可以进行腌制。

(Suggested by Antoine Pitrou and Jesse Noller. Implemented by Jack Diederich; issue 5228.)
  • 添加符号的pydoc帮助主题,以便help('@')在交互式环境中正常工作。

    (由David Laban提供; 问题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
    

    In addition, several new assertion methods were added including assertSetEqual(), assertDictEqual(), assertDictContainsSubset(), assertListEqual(), assertTupleEqual(), assertSequenceEqual(), assertRaisesRegexp(), assertIsNone(), and assertIsNotNone().

    (由Benjamin Peterson和Antoine Pitrou提供)

  • io模块对seek()方法SEEK_SETSEEK_CURSEEK_END

  • sys.version_info元组现在是一个命名的元组:

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

    (由Ross Light提供; 第4285期。)

  • nntplibimaplib模块现在支持IPv6。

    (由Derek Morr提供; 问题1655问题1664。)

  • 当使用协议2或更低版本时,pickle模块已经适用于与Python 2.x更好的互操作性。标准库的重组改变了许多对象的形式参考。例如,Python 2中的__builtin__.set在Python 3中称为builtins.set这种改变混淆了在不同版本的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腌菜将不能用Python 3.0读取。在Python 3.x实现之间迁移数据时,应使用最新的pickle协议(协议3),因为它不会尝试与Python 2.x保持兼容。

    (由Alexandre Vassalotti和Antoine Pitrou提供,问题6137。)

  • 添加了一个新模块,importlib它提供了import语句及其对应的__import__()函数的完整,可移植,纯Python参考实现。它是在记录和界定进口期间所采取的行动方面迈出的重要一步。

    (由Brett Cannon提供。)

Optimizations

已添加主要性能增强功能:

  • 新的I / O库(在 PEP 3116中定义)大多是用Python编写的,并且很快被证明是Python 3.0中的一个有问题的瓶颈。在Python 3.1中,I / O库已完全在C中重写,并且根据手头的任务快2到20倍。纯Python版本仍可通过_pyio模块进行实验。

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

  • 添加启发式,以便包含只有不可追踪的对象的元组和dicts不会被垃圾收集器跟踪。这可以减少容器的大小,并因此减少长时间运行的程序的垃圾容器开销,这取决于它们特定的数据类型的使用。

    (由Antoine Pitrou提供,issue 4688。)

  • 在支持它的编译器(尤其是gcc,SunPro,icc)上启用名为--with-computed-gotos的配置选项,字节码评估循环使用新的调度机制进行编译,到20%,具体取决于系统,编译器和基准测试。

    (由Antoine Pitrou以及一些其他参与者提供,问题4753)。

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

    (由Antoine Pitrou和Amaury Forgeot d'Arc提供,问题4868。)

  • json模块现在具有C扩展以显着提高其性能。此外,API已修改,以使json仅与str,而不与bytes该更改使该模块与按照Unicode定义的JSON规范紧密匹配。

    (由Bob Ippolito提供并由Antoine Pitrou和Benjamin Peterson转换为Py3.1; 问题4136。)

  • Unpickling现在实习了腌制对象的属性名称。这节省了内存,并允许酱菜更小。

    (由Jake McGuire和Antoine Pitrou提供; 第5084期。)

IDLE

  • IDLE的格式菜单现在提供一个选项来从源文件中去除空格。

    (由Roger D. Serwy提供; 问题5150。)

Build and C API Changes

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

  • 整数现在存储在内部基础2 ** 15或基础2 ** 30,基础在构建时确定。以前,他们总是存储在基地2 ** 15。使用base 2 ** 30在64位机器上提供了显着的性能改进,但是在32位机器上的基准测试结果是混合的。因此,默认是在64位机器上使用base 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提供; 问题4258。)

  • PyLong_AsUnsignedLongLong()现在通过提高OverflowError而不是TypeError来处理负的pylong

    (由Mark Dickinson和Lisandro Dalcrin提供; 问题5175。)

  • 已弃用PyNumber_Int()使用PyNumber_Long()

    (由Mark Dickinson提供; 第4910期。)

  • 添加了一个新的PyOS_string_to_double()函数来替换已弃用的函数PyOS_ascii_strtod()PyOS_ascii_atof()

    (供稿人:Mark Dickinson; 第5914期。)

  • 添加PyCapsule作为PyCObject API的替代品。主要的区别是新类型有一个良好定义的接口用于传递打字安全信息和一个较不复杂的声明调用析构函数。旧类型有一个有问题的API,现在已被弃用。

    (由Larry Hastings提供; 问题5630。)

Porting to Python 3.1

本节列出了之前描述的更改和其他可能需要更改代码的错误:

  • 新的浮点字符串表示可以打破现有的doctests。例如:

    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 pickles在Python 3.0中不可读。一个解决方案是使用协议3。另一个解决方案是将fix_imports选项设置为False有关详细信息,请参阅上面的讨论。