Python 3.1 新增Function

  • Author

    • Raymond Hettinger

本文介绍了 Python 3.1 与 3.0 相比的新Function。

PEP 372:Order 字典

常规 Python 字典以任意 Sequences 遍历键/值对。多年来,许多作者编写了替代实现,这些实现记住了最初插入密钥的 Sequences。基于这些实现的经验,引入了一个新的collections.OrderedDict类。

OrderedDict API 与常规词典基本相同,但会根据保证首次插入键的时间以保证的 Sequences 遍历键和值。如果新条目覆盖现有条目,则原始插入位置将保持不变。删除条目并重新插入将其移至末尾。

现在,标准库支持在多个模块中使用有序词典。 configparser模块默认使用它们。这使配置文件可以按其原始 Sequences 进行读取,修改和写回。 collections.namedtuple()的* _asdict()方法现在返回一个有序字典,其值与基础 Tuples 索引的显示 Sequences 相同。 json模块正在使用 object_pairs_hook *构建,以允许解码器构建 OrderedDicts。还添加了对诸如PyYAML之类的第三方工具的支持。

See also

  • PEP 372-Order 字典

  • PEP 由 Armin Ronacher 和 Raymond Hettinger 撰写。由 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 *格式说明符,该说明符已经对数千个分隔符提供了一些支持。

See also

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

  • PEP 由 Raymond Hettinger 撰写,由 Eric Smith 和 Mark Dickinson 实施。

其他语言更改

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

  • 现在,可以将包含__main__.py文件的目录和 zip 存档直接传递给解释器,以执行它们。目录/ zipfile 将作为第一个条目自动插入 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。)

(由 Georg Brandl 提供; bpo-5675。)

  • with语句的语法现在允许在单个语句中使用多个上下文 Management 器:
>>> 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 提供; bpo-4707。)

  • Python 现在使用 David Gay 的算法来查找不会更改其值的最短浮点表示形式。这应该有助于减轻围绕二进制浮点数的一些困惑。

1.1这样的数字可以很容易地看出其重要性,该数字在二进制浮点数中没有完全等效的值。由于没有精确的等效项,因此像float('1.1')这样的表达式求值到最接近的可表示值,即十六进制0x1.199999999999ap+0或十进制1.100000000000000088817841970012523233890533447265625。该最接近的值曾经且仍在以后的浮点计算中使用。

新Function是显示数字的方式。以前,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,仍然是1.1 + 2.2 != 3.3的情况。

新算法取决于基础浮点实现中的某些Function。如果找不到所需的Function,则将 continue 使用旧算法。而且,文本 pickle 协议pass使用旧算法来确保跨平台的可移植性。

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

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

  • 添加了collections.Counter类以支持方便地按 Sequences 或可迭代方式对唯一项进行计数:
>>> 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。)

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

>>> [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 等的位置名称。当字段名称由外部源(例如 CSVHeaders,SQL 字段)创建时,此Function很有用列表或用户 Importing:
>>> 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。)

(由格雷戈里·史密斯(Gregory Smith)贡献。)

  • 现在,logging模块为不使用日志记录但正在调用库代码的应用程序实现一个简单的logging.NullHandler类。设置 null 处理程序将抑制虚假警告,例如“找不到 logger foo 处理程序”:
>>> h = logging.NullHandler()
>>> logging.getLogger("foo").addHandler(h)

(由 Vinay Sajip 提供; bpo-4384)。

  • 现在,支持-m命令行开关的runpy模块pass提供软件包名称来查找并执行__main__子模块来支持软件包的执行。

(由 Andi Vajda 提供; bpo-4195。)

  • pdb模块现在可以访问和显示passzipimport(或任何其他符合要求的 PEP 302加载程序)加载的源代码。

(由 Alexander Belopolsky 提供; bpo-4201。)

Note

(由 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语句对异常测试进行了构建以与上下文 Management 器一起使用:

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

此外,添加了几种新的 assert 方法,包括assertSetEqual()assertDictEqual()assertDictContainsSubset()assertListEqual()assertTupleEqual()assertSequenceEqual()assertRaisesRegexp()assertIsNone()assertIsNotNone()

(由本杰明·彼得森和安托万·皮特鲁贡献.)

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

  • sys.version_infoTuples 现在是一个命名 Tuples:

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

(由 Ross Light 提供; bpo-4285。)

(由 Derek Morr; bpo-1655bpo-1664贡献。)

  • 当与协议 2 或更低版本一起使用时,pickle模块已经过改进,可以更好地与 Python 2.x 互操作。标准库的重组改变了许多对象的正式参考。例如,Python 2 中的__builtin__.set在 Python 3 中称为builtins.set。此更改使在不同版本的 Python 之间共享数据的工作变得混乱。但是现在选择协议 2 或更低版本时,selectors 将自动使用旧的 Python 2 名称进行加载和转储。默认情况下,此重新 Map 是打开的,但可以pass* 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 无法读取 Python 3.1 产生的协议 2pickle。在 Python 3.x 实现之间迁移数据时,应使用最新的 pickle 协议(协议 3),因为它不会try与 Python 2.x 保持兼容。

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

  • 添加了一个新模块importlib。它提供import语句及其对应的import()函数的完整,可移植的纯 Python 参考实现。它代表了在记录和定义导入期间发生的操作方面迈出的重要一步。

(由布雷特·坎农(Brett Cannon)贡献。)

Optimizations

主要性能增强已添加:

  • 新的 I/O 库(在 PEP 3116中定义)大部分是用 Python 编写的,并很快被证明是 Python 3.0 中的问题瓶颈。在 Python 3.1 中,I/O 库已完全用 C 语言重写,并且根据手头的任务要快 2 至 20 倍。仍然可以pass_pyio模块将纯 Python 版本用于实验目的。

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

  • 添加了一种启发式方法,以便垃圾收集器不会跟踪仅包含不可跟踪对象的 Tuples 和字典。这可以减少收集的大小,从而减少长时间运行的程序上的垃圾收集开销,具体取决于它们对数据类型的特殊使用。

(由 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模块现在具有 Cextensions,可以大大改善其性能。此外,已对 API 进行了修改,以便 json 仅适用于str,不适用于bytes。所做的更改使模块与 Unicode 定义的JSON specification紧密匹配。

(由 Bob Ippolito 贡献,并由 Antoine Pitrou 和 Benjamin Peterson 转换为 Py3.1; bpo-4136。)

  • 现在,取消腌制会实习腌制对象的属性名称。这样可以节省内存,并使 pickle 更小。

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

IDLE

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

(由 Roger D. Serwy 提供; bpo-5150。)

Build 和 C API 的更改

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

  • 现在,整数在内部存储在 base 2 15 或 base 2 30 中,该基数是在构建时确定的。以前,它们始终以 2 15 为基数存储.使用基数 2 30 可以在 64 位计算机上显着提高性能,但是在 32 位计算机上的基准测试结果参差不齐。因此,默认值是在 64 位计算机上使用 base 2 30,在 32 位计算机上使用 base 2 15.在 Unix 上,有一个新的配置选项--enable-big-digits可用于覆盖此默认值。

除了性能改进之外,此更改对finally用户应该是不可见的,只有一个 exception:为了测试和调试目的,有一个新的sys.int_info提供有关内部格式的信息,给出了每位的位数和 C 语言的字节大小。用于存储每个数字的类型:

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

(由 Mark Dickinson 提供; bpo-4258。)

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

(由 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
**********************************************************************
  • 协议 2 或更低版本的 pickle 模块中的自动名称重新 Map 可能使 Python 3.1 pickle 在 Python 3.0 中不可读。一种解决方案是使用协议 3.另一种解决方案是将* fix_imports *选项设置为False。有关更多详细信息,请参见上面的讨论。