在Python中,如何知道对象是否可以比较?
In Python, how to know whether objects can be compared?
与abstract base classes, Python provides a way to know the behavior of objects without actually trying it out. In the standard library, we have some ABCs defined for containers in collections.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
我希望有一个这样的 ABC 来决定是否可以比较 class 的实例,但找不到。测试 __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
所以我的问题是:有没有一种简单的方法可以做到这一点而无需自己进行比较并捕获 TypeError
?
我的用例类似于排序容器:我想在插入第一个元素时引发异常,而不是等待第二个元素。我考虑过将元素与自身进行比较,但有没有更好的方法:
def insert(self, element):
try:
element < element
except TypeError as e:
raise TypeError('element must be comparable.')
# do stuff
不,没有这样的 ABC,因为 ABC 只说明那里有什么属性。 ABC 无法测试实现的性质(或者即使这些属性实际上是方法)。
存在比较方法(__lt__
、__gt__
、__le__
、__ge__
和 __eq__
)不 指示 class 将与其他所有内容相媲美。 通常只能比较同类型或class类型的对象;数字以数字为例。
因此,大多数类型*实现比较方法,但returnNotImplemented
哨兵对象当与其他不兼容的类型进行比较。将 NotImplemented
信号返回给 Python 也让右边的值在这个问题上有发言权。如果 a.__lt__(b)
returns NotImplemented
那么 b.__gt__(a)
也被测试了。
基础 object
提供方法的默认实现,returning 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
这正是 dict.__lt__
所做的:
>>> {}.__lt__({})
NotImplemented
数字,但是,只有 return 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()
因此,您的最佳选择是简单地捕获当值不可比较时抛出的TypeError
。
* 我不知道 Python 3 标准库中的任何类型目前没有实现比较方法。
与abstract base classes, Python provides a way to know the behavior of objects without actually trying it out. In the standard library, we have some ABCs defined for containers in collections.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
我希望有一个这样的 ABC 来决定是否可以比较 class 的实例,但找不到。测试 __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
所以我的问题是:有没有一种简单的方法可以做到这一点而无需自己进行比较并捕获 TypeError
?
我的用例类似于排序容器:我想在插入第一个元素时引发异常,而不是等待第二个元素。我考虑过将元素与自身进行比较,但有没有更好的方法:
def insert(self, element):
try:
element < element
except TypeError as e:
raise TypeError('element must be comparable.')
# do stuff
不,没有这样的 ABC,因为 ABC 只说明那里有什么属性。 ABC 无法测试实现的性质(或者即使这些属性实际上是方法)。
存在比较方法(__lt__
、__gt__
、__le__
、__ge__
和 __eq__
)不 指示 class 将与其他所有内容相媲美。 通常只能比较同类型或class类型的对象;数字以数字为例。
因此,大多数类型*实现比较方法,但returnNotImplemented
哨兵对象当与其他不兼容的类型进行比较。将 NotImplemented
信号返回给 Python 也让右边的值在这个问题上有发言权。如果 a.__lt__(b)
returns NotImplemented
那么 b.__gt__(a)
也被测试了。
基础 object
提供方法的默认实现,returning 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
这正是 dict.__lt__
所做的:
>>> {}.__lt__({})
NotImplemented
数字,但是,只有 return 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()
因此,您的最佳选择是简单地捕获当值不可比较时抛出的TypeError
。
* 我不知道 Python 3 标准库中的任何类型目前没有实现比较方法。