如果在Python中使用duck-typing,你应该测试isinstance吗?

时间:2012-03-23 17:14:55

标签: python equality duck-typing

你有一个需要等于测试的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

3 个答案:

答案 0 :(得分:13)

__eq__方法中使用isinstance很常见。这样做的原因是,如果__eq__方法失败,它可以从另一个对象的__eq__方法回退。大多数常规方法都是显式调用的,但__eq__是隐式调用的,所以它需要更频繁地查看先跳。

编辑(感谢提醒,Sven Marnach):

要使其回退,您可以返回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属性,但“请求宽恕比获得许可更容易”)