Python中int和numbers.Integral的区别

24 投票
4 回答
11849 浏览
提问于 2025-04-17 06:42

我正在努力深入理解Python的数据模型,但对以下代码还不是很明白:

>>> x = 1

>>> isinstance(x,int)
True

>>> isinstance(x,numbers.Integral)
True

>>> inspect.getmro(int)
(<type 'int'>, <type 'object'>)

>>> inspect.getmro(numbers.Integral)
(<class 'numbers.Integral'>, <class 'numbers.Rational'>, <class 'numbers.Real'>,
 <class 'numbers.Complex'>, <class 'numbers.Number'>, <type 'object'>)

根据上面的内容,似乎intnumber.Integral并不在同一个层级里。

从Python的参考资料(2.6.6)中,我看到:

numbers.Integral - 这些代表数学中整数的集合(包括正整数和负整数)。

那么intnumbers.Integral之间有什么区别呢?这和我在上面看到的type intclass numbers.Integral有关系吗?

4 个回答

5

简而言之:int 被注册为 numbers.Integral 的一个虚拟子类。

# numbers.py:380 (CPython 3.8)
Integral.register(int)

numbers.Integral 是对整数应该具备的特性的一个抽象定义,而 int 则是整数的具体实现。


isinstanceissubclass 这两个函数并不仅仅用于继承关系。比如,它们可以用来表示像 collections.abc.Iterable 这样的结构类型关系:

>>> class MyIterable:
...     def __iter__(self): ...
...
>>> issubclass(MyIterable, collections.abc.Iterable)
True

实际上,isinstanceissubclass 可以针对每种类型进行 自定义。标准库利用这一点来定义 抽象基类(ABC),支持具体的子类(通过继承)和虚拟子类(通过 cls.register(subclass))。

虚拟子类并不是通过继承与它的 ABC 相关联,因此它的方法解析顺序不会使用 ABC。具体来说,int 并没有 继承 numbers.Integral 的任何方法。不过,它确实 实现numbers.Integral 所要求的所有公共方法和操作,因而满足了 numbers.Integral 的定义。

5

让我补充两点:

isinstance(x,numbers.Integral)

还包括 long

isinstance(x, int)

不包括。numbers.Integral 的测试会更接近于

isinstance(x, (int, long))

在 Python 2 中(Python 3 彻底去掉了 long)。

我更喜欢使用 numbers.Integral 的测试,因为如果你是从 int(或者 long)派生的,isinstance(y, numbers.Integral) 仍然会返回 True

12

numbers 是一组抽象类的集合,这些抽象类定义了对数字类型可以进行的操作。你可以查看一下 PEP 3141 来了解更多。intIntegral 之间的区别在于,int 是一种具体的类型,它支持 Integral 定义的所有操作。

撰写回答