你有一个需要等于测试的Python类。 Python应该使用duck-typing但是(更好/更准确)在 eq 函数中包含或排除isinstance测试?例如:
class Trout(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return isinstance(other, Trout) and self.value == other.value
答案 0 :(得分:13)
在__eq__
方法中使用isinstance很常见。这样做的原因是,如果__eq__
方法失败,它可以从另一个对象的__eq__
方法回退。大多数常规方法都是显式调用的,但__eq__
是隐式调用的,所以它需要更频繁地查看先跳。
要使其回退,您可以返回NotImplemented单例,如下例所示:
class Trout(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
if isinstance(other, Trout):
return self.value == other.value
else:
return NotImplemented
假设RainbowTrout
知道如何将自己与Trout
或另一个RainbowTrout
进行比较,但Trout
只知道如何将自身与{{1}进行比较}。在此示例中,如果您测试Trout
,Python将首先调用mytrout == myrainbowtrout
,注意它失败,然后调用成功的mytrout.__eq__(myrainbowtrout)
。
答案 1 :(得分:6)
在isintsance()
方法中使用__eq__()
通常很好。如果False
检查失败,则不应立即返回isinstance()
- 最好返回NotImplemented
以使other.__eq__()
有机会被执行:
def __eq__(self, other):
if isinstance(other, Trout):
return self.x == other.x
return NotImplemented
这在多个类定义__eq__()
:
class A(object):
def __init__(self, x):
self.x = x
def __eq__(self, other):
if isinstance(other, A):
return self.x == other.x
return NotImplemented
class B(A):
def __init__(self, x, y):
A.__init__(self, x)
self.y = y
def __eq__(self, other):
if isinstance(other, B):
return self.x, self.y == other.x, other.y
return NotImplemented
如果您立即返回False
,就像在原始代码中一样,您将失去A(3) == B(3, 4)
和B(3, 4) == A(3)
之间的对称性。
答案 2 :(得分:4)
“鸭子打字”原则是你不关心other
是什么,只要它具有value
属性。因此,除非您的属性共享具有冲突语义的名称,否则我建议这样做:
def __eq__(self, other):
try:
return self.value == other.value
except AttributeError:
return False # or whatever
(或者,您可以测试other
是否具有value
属性,但“请求宽恕比获得许可更容易”)