Fra*_*las 4 python comparison-operators abstract-base-class python-3.x
通过抽象基类,Python 提供了一种无需实际尝试即可了解对象行为的方法。在标准库中,我们为collections.abc 中的容器定义了一些 ABC 。例如,可以测试一个参数是否可迭代:
from collections.abc import Iterable
def function(argument):
if not isinstance(argument, Iterable):
raise TypeError('argument must be iterable.')
# do stuff with the argument
Run Code Online (Sandbox Code Playgroud)
我希望有一个这样的 ABC 来决定是否可以比较一个类的实例但找不到一个。测试__lt__方法的存在是不够的。例如,字典不能比较,但__lt__仍然是定义的(与object实际相同)。
>>> d1, d2 = {}, {}
>>> d1 < d2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()
>>> hasattr(d1, '__lt__')
True
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:有没有一种简单的方法来做到这一点,而无需自己进行比较并捕捉到 TypeError?
我的用例类似于排序的容器:我想在插入第一个元素时引发异常,而不是等待第二个元素。我想过将元素与其自身进行比较,但有没有更好的方法:
def insert(self, element):
try:
element < element
except TypeError as e:
raise TypeError('element must be comparable.')
# do stuff
Run Code Online (Sandbox Code Playgroud)
不,没有这样的 ABC,因为 ABC只规定了那里的属性。ABC 无法测试实现的性质(或者即使这些属性实际上是方法)。
比较方法存在(__lt__,__gt__,__le__,__ge__和__eq__)也没有规定该班将是与一切相媲美。通常你只能比较相同类型或类型的类的对象;以数字为例。
因此,大多数类型*实现了比较方法,但NotImplemented在与其他不兼容类型进行比较时返回标记对象。将NotImplemented信号返回给 Python 以在这件事上给右手值一个发言权。如果a.__lt__(b)返回,NotImplemented则b.__gt__(a)也进行测试。
基础object提供了方法的默认实现,返回NotImplemented:
>>> class Foo:
... pass
...
>>> Foo() < Foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Foo() < Foo()
>>> Foo().__lt__
<method-wrapper '__lt__' of Foo object at 0x10f1cf860>
>>> Foo().__lt__(Foo())
NotImplemented
Run Code Online (Sandbox Code Playgroud)
这正是dict.__lt__:
>>> {}.__lt__({})
NotImplemented
Run Code Online (Sandbox Code Playgroud)
但是,数字仅NotImplemented在其他类型不可比较时才返回:
>>> (1).__lt__(2)
True
>>> (1).__lt__('2')
NotImplemented
>>> 1 < 2
True
>>> 1 < '2'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
Run Code Online (Sandbox Code Playgroud)
因此,您最好的选择是TypeError在值不可比较时简单地捕获抛出的值。
* 目前我不知道 Python 3 标准库中没有实现比较方法的任何类型。