Python中int和numbers.Integral的区别
我正在努力深入理解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'>)
根据上面的内容,似乎int
和number.Integral
并不在同一个层级里。
从Python的参考资料(2.6.6)中,我看到:
numbers.Integral - 这些代表数学中整数的集合(包括正整数和负整数)。
那么int
和numbers.Integral
之间有什么区别呢?这和我在上面看到的type int
和class numbers.Integral
有关系吗?
4 个回答
简而言之:int
被注册为 numbers.Integral
的一个虚拟子类。
# numbers.py:380 (CPython 3.8)
Integral.register(int)
numbers.Integral
是对整数应该具备的特性的一个抽象定义,而 int
则是整数的具体实现。
isinstance
和 issubclass
这两个函数并不仅仅用于继承关系。比如,它们可以用来表示像 collections.abc.Iterable
这样的结构类型关系:
>>> class MyIterable:
... def __iter__(self): ...
...
>>> issubclass(MyIterable, collections.abc.Iterable)
True
实际上,isinstance
和 issubclass
可以针对每种类型进行 自定义。标准库利用这一点来定义 抽象基类(ABC),支持具体的子类(通过继承)和虚拟子类(通过 cls.register(subclass)
)。
虚拟子类并不是通过继承与它的 ABC 相关联,因此它的方法解析顺序不会使用 ABC。具体来说,int
并没有 继承 numbers.Integral
的任何方法。不过,它确实 实现 了 numbers.Integral
所要求的所有公共方法和操作,因而满足了 numbers.Integral
的定义。
让我补充两点:
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
。
numbers
是一组抽象类的集合,这些抽象类定义了对数字类型可以进行的操作。你可以查看一下 PEP 3141 来了解更多。int
和 Integral
之间的区别在于,int
是一种具体的类型,它支持 Integral
定义的所有操作。