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 程序员(无论他们是否熟悉编程)少学习一项内容,才能开始使用该语言。
实现
最初,提出了两种替代的实现方案(每位作者提出一个)
PyInt
类型的 C long 槽位将变成一个union { long i; struct { unsigned long length; digit digits[1]; } bignum; };
只有
long
的低n-1
位有意义;最高位始终设置。这区分了union
。所有PyInt
函数都会检查此位,然后决定使用哪种类型的操作。- 现有的短整数和长整数类型仍然存在,但操作将返回长整数,而不是在结果不能表示为短整数时引发
OverflowError
。可能会引入一个新的类型integer
,它是一个抽象基类型,int
和long
实现类型都是它的子类。这很有用,因为程序可以使用单个测试检查整数性if isinstance(i, integer): ...
经过仔细考虑,选择了第二个实现计划,因为它更容易实现,在 C API 级别向后兼容,此外还可以作为过渡措施部分实现。
不兼容性
以下操作在短整数和长整数中具有(通常是细微的)不同的语义,其中一个或另一个将不得不进行某种改变。这应该是一个详尽的列表。如果您知道任何其他操作,其结果会因传递相同值的短整数或长整数而异,请写信给第二作者。
- 目前,对短整数的所有算术运算符(除了
<<
)都会在结果不能表示为短整数时引发OverflowError
。这将改为返回长整数。以下运算符目前可能引发OverflowError
:x+y
、x-y
、x*y
、x**y
、divmod(x, y)
、x/y
、x%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
模块以及pickle
和cPickle
模块对长整数和短整数的处理方式不同。这种差异将仍然存在(至少在 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 长整数。
过渡
过渡主要分为三个阶段
- 目前引发
OverflowError
的短整数运算将改为返回长整数的值。这是此阶段唯一的更改。字面量仍将区分短整数和长整数。上面列出的其他语义差异(包括<<
的行为)将保留。由于此阶段只改变了当前引发OverflowError
的情况,因此假设这不会破坏现有代码。(依赖此异常的代码将过于复杂,无法担心它。)对于那些关心极端向后兼容性的人,可以使用命令行选项(或对 warnings 模块的调用)在此处发出警告或错误,但默认情况下是关闭的。 - 解决剩余的语义差异。在所有情况下,都将以长整数语义为主。由于这将引入破坏某些旧代码的向后不兼容性,因此此阶段可能需要一个 future 语句和/或警告,以及一个长时间的过渡阶段。尾部 L 将继续用于 longs 作为输入,并由
repr()
使用。- 在 2B 阶段,将启用关于会改变数值结果的操作的警告,特别是
hex()
和oct()
、%u
、%x
、%X
和%o
、hex
和oct
字面量在(包含)范围[sys.maxint+1, sys.maxint*2+1]
内,以及丢失位的左移操作。 - 这些操作的新语义已实现。与以前结果不同的操作 *不会* 发出警告。
- 在 2B 阶段,将启用关于会改变数值结果的操作的警告,特别是
- 从
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