Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 237 – 统一长整数和整数

作者:
Moshe Zadka,Guido van Rossum
状态:
最终
类型:
标准跟踪
创建:
2001 年 3 月 11 日
Python 版本:
2.2
历史记录:
2001 年 3 月 16 日,2001 年 8 月 14 日,2001 年 8 月 23 日

目录

摘要

Python 目前区分两种整数(int):普通或短整数,受 C long 大小限制(通常为 32 或 64 位),以及长整数,仅受可用内存限制。当对短整数的操作产生不适合 C long 的结果时,会引发错误。还有一些其他区别。本 PEP 提出消除大多数语义上的差异,从 Python 用户的角度统一这两种类型。

基本原理

许多程序在事后发现需要处理更大的数字,而之后更改算法则很麻烦。当所有算术运算都使用长整数执行时,无论它们是否需要,都会影响性能。

让机器字长暴露给语言会阻碍可移植性。例如,由于这个原因,Python 源文件和 .pyc 文件在 32 位和 64 位机器之间不可移植。

人们还普遍希望在大多数应用程序中无关紧要时,将不必要的细节隐藏在 Python 用户面前。例如,内存分配在 C 中是显式的,而在 Python 中是自动的,这为我们提供了字符串、列表等无限大小的便利。将这种便利扩展到数字是很有意义的。

这将使新的 Python 程序员(无论他们是否熟悉编程)少学习一项内容,才能开始使用该语言。

实现

最初,提出了两种替代的实现方案(每位作者提出一个)

  1. PyInt 类型的 C long 槽位将变成一个
    union {
        long i;
        struct {
            unsigned long length;
            digit digits[1];
        } bignum;
    };
    

    只有 long 的低 n-1 位有意义;最高位始终设置。这区分了 union。所有 PyInt 函数都会检查此位,然后决定使用哪种类型的操作。

  2. 现有的短整数和长整数类型仍然存在,但操作将返回长整数,而不是在结果不能表示为短整数时引发 OverflowError。可能会引入一个新的类型 integer,它是一个抽象基类型,intlong 实现类型都是它的子类。这很有用,因为程序可以使用单个测试检查整数性
    if isinstance(i, integer): ...
    

经过仔细考虑,选择了第二个实现计划,因为它更容易实现,在 C API 级别向后兼容,此外还可以作为过渡措施部分实现。

不兼容性

以下操作在短整数和长整数中具有(通常是细微的)不同的语义,其中一个或另一个将不得不进行某种改变。这应该是一个详尽的列表。如果您知道任何其他操作,其结果会因传递相同值的短整数或长整数而异,请写信给第二作者。

  • 目前,对短整数的所有算术运算符(除了 <<)都会在结果不能表示为短整数时引发 OverflowError。这将改为返回长整数。以下运算符目前可能引发 OverflowErrorx+yx-yx*yx**ydivmod(x, y)x/yx%y-x。(最后四个只有在值 -sys.maxint-1 参与时才会溢出。)
  • 目前,x<<n 可能会丢失短整数的位。这将改为返回一个长整数,其中包含所有移位的位(如果返回短整数会丢失位(其中改变符号被认为是丢失位的特殊情况))。
  • 目前,短整数的十六进制和八进制字面量可以指定负值;例如,在 32 位机器上,0xffffffff == -1。这将改为等于 0xffffffffL (2**32-1)。
  • 目前,%u%x%X%o 字符串格式化运算符以及 hex()oct() 内置函数对负数的行为不同:负短整数被格式化为无符号 C long,而负长整数被格式化为带减号。这将改为在所有情况下使用长整数语义(但不会使用当前区分 hex()oct() 用于长整数的输出的尾部 L)。请注意,这意味着 %u 成为 %d 的别名。它最终会被删除。
  • 目前,长整数的 repr() 返回一个以 L 结尾的字符串,而短整数的 repr() 则没有。L 将被删除;但不会在 Python 3.0 之前。
  • 目前,具有长操作数的操作永远不会返回短整数。这可能会改变,因为它允许进行一些优化。(此领域还没有做出任何改变,也没有任何计划。)
  • 表达式 type(x).__name__ 取决于 x 是短整数还是长整数。由于选择了实现方案 2,这种差异将仍然存在。(在 Python 3.0 中,我们可能能够使用一个技巧来隐藏这种差异,因为向用户代码公开这种差异很烦人,而且随着两种类型之间的差异越来越不明显,这种做法就更烦人了。)
  • marshal 模块以及 picklecPickle 模块对长整数和短整数的处理方式不同。这种差异将仍然存在(至少在 Python 3.0 之前)。
  • 具有较小值的短整数(通常在 -1 到 99 之间,包括这两个值)会被驻留——每当出现一个具有该值的结

字面量

整数字面量结尾处的 L 将不再具有任何意义,最终将变得非法。编译器将仅根据值选择合适的类型。(在 Python 3.0 之前,它将强制将字面量设置为长整数;但没有尾部 L 的字面量也可能是长整数,如果它们不能表示为短整数。)

内置函数

int() 函数将根据参数值返回短整数或长整数。在 Python 3.0 中,long() 函数将调用 int() 函数;在此之前,它将继续强制将结果设置为长整数,但在其他方面与 int() 函数的工作方式相同。内置名称 long 将保留在语言中以表示长整数实现类型(除非它在 Python 3.0 中被完全消除),但仍然建议使用 int() 函数,因为它会在需要时自动返回长整数。

C API

C API 保持不变;C 代码仍然需要知道短整数和长整数之间的区别。(Python 3.0 C API 可能完全不兼容。)

PyArg_Parse*() API 已经接受长整数,只要它们在 C int 或 long 可表示的范围内,这样接受 C int 或 long 参数的函数就不必担心处理 Python 长整数。

过渡

过渡主要分为三个阶段

  1. 目前引发 OverflowError 的短整数运算将改为返回长整数的值。这是此阶段唯一的更改。字面量仍将区分短整数和长整数。上面列出的其他语义差异(包括 << 的行为)将保留。由于此阶段只改变了当前引发 OverflowError 的情况,因此假设这不会破坏现有代码。(依赖此异常的代码将过于复杂,无法担心它。)对于那些关心极端向后兼容性的人,可以使用命令行选项(或对 warnings 模块的调用)在此处发出警告或错误,但默认情况下是关闭的。
  2. 解决剩余的语义差异。在所有情况下,都将以长整数语义为主。由于这将引入破坏某些旧代码的向后不兼容性,因此此阶段可能需要一个 future 语句和/或警告,以及一个长时间的过渡阶段。尾部 L 将继续用于 longs 作为输入,并由 repr() 使用。
    1. 在 2B 阶段,将启用关于会改变数值结果的操作的警告,特别是 hex()oct()%u%x%X%ohexoct 字面量在(包含)范围 [sys.maxint+1, sys.maxint*2+1] 内,以及丢失位的左移操作。
    2. 这些操作的新语义已实现。与以前结果不同的操作 *不会* 发出警告。
  3. repr() 中删除了尾部的 *L*,并在输入时将其标记为非法。(如果可能,long 类型将完全消失。)尾部的 *L* 也从 hex()oct() 中删除。

阶段 1 将在 Python 2.2 中实现。

阶段 2 将逐步实现,2A 在 Python 2.3 中,2B 在 Python 2.4 中。

阶段 3 将在 Python 3.0 中实现(至少在 Python 2.4 发布两年后)。

OverflowWarning

以下是指导在当前引发 OverflowError 的情况下生成的警告的规则。这适用于过渡阶段 1。历史记录:尽管阶段 1 在 Python 2.2 中完成,阶段 2A 在 Python 2.3 中完成,但没有人注意到 Python 2.3 中仍然生成 OverflowWarning。它最终在 Python 2.4 中被禁用。Python 内置的 OverflowWarning 以及相应的 C API PyExc_OverflowWarning 在 Python 2.4 中不再生成或使用,但在 Python 2.5 之前,对于用户代码(可能性很小)将保留。

  • 引入了新的警告类别,OverflowWarning。这是一个内置名称。
  • 如果 int 结果溢出,将发出 OverflowWarning 警告,并带有指示操作的消息参数,例如“整数加法”。这可能会或可能不会导致在 sys.stderr 上显示警告消息,或导致引发异常,所有这些都受 -W 命令行和 warnings 模块的控制。
  • 默认情况下忽略 OverflowWarning 警告。
  • 可以使用与所有警告相同的控制方式控制 OverflowWarning 警告,通过 -W 命令行选项或通过 warnings.filterwarnings() 调用。例如
    python -Wdefault::OverflowWarning
    

    导致 OverflowWarning 在特定源代码行第一次出现时显示,以及

    python -Werror::OverflowWarning
    

    导致 OverflowWarning 变成异常,无论何时发生。以下代码从程序内部启用警告

    import warnings
    warnings.filterwarnings("default", "", OverflowWarning)
    

    有关 -W 选项,请参见 python 的 man 页面,有关 filterwarnings(),请参见 warnings 模块文档。

  • 如果 OverflowWarning 警告变成了错误,则用 OverflowError 替换。这是为了向后兼容。
  • 除非警告变成了异常,否则操作的结果(例如,x+y)将在将参数转换为长整数后重新计算。

示例

如果将长整数传递给接受整数的 C 函数或内置操作,只要值适合(根据 PyArg_ParseTuple() 的实现方式),它将被视为短整数。如果长整数不适合,它仍然会引发 OverflowError。例如

def fact(n):
    if n <= 1:
    return 1
return n*fact(n-1)

A = "ABCDEFGHIJKLMNOPQ"
n = input("Gimme an int: ")
print A[fact(n)%17]

对于 n >= 13,这当前会引发 OverflowError(除非用户在输入中输入尾部的 *L*),即使计算出的索引始终在 range(17) 内。使用新方法,此代码将执行正确操作:索引将被计算为长整数,但其值将在范围内。

已解决的问题

这些以前未解决的问题现已得到解决。

  • 应用于长整数的 hex()oct() 将继续产生尾部的 *L*,直到 Python 3000。上面的原始文本对此并不清楚,但由于它在 Python 2.4 中没有发生,所以认为最好不要修改它。BDFL 声明如下

    https://mail.python.org/pipermail/python-dev/2006-June/065918.html

  • 如何处理 sys.maxint?保留它,因为它在短整数和长整数之间的区别仍然相关时仍然相关(例如,当检查值的类型时)。
  • 我们应该完全删除 %u 吗?删除它。
  • 我们是否应该警告 << 没有截断整数?是的。
  • 溢出警告是否应该基于便携式最大大小?不。

实现

Python 2.x 线的实现工作已完成;阶段 1 随 Python 2.2 发布,阶段 2A 随 Python 2.3 发布,阶段 2B 将随 Python 2.4 发布(并且已在 CVS 中)。


来源:https://github.com/python/peps/blob/main/peps/pep-0237.rst

最后修改时间:2023-09-09 17:39:29 GMT