18

你有一个 Python 类,它需要一个 equals 测试。Python 应该使用鸭子类型,但是在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
4

3 回答 3

16

在方法中使用 isinstance__eq__很常见。这样做的原因是,如果__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

假设 aRainbowTrout知道如何将自己与 aTrout或另一个进行比较RainbowTrout,但 aTrout只知道如何将自己与 a 进行比较Trout。在这个例子中,如果你 test mytrout == myrainbowtrout,Python 将首先调用mytrout.__eq__(myrainbowtrout),注意到它失败了,然后调用myrainbowtrout.__eq__(mytrout),它成功了。

于 2012-03-23T17:22:15.447 回答
8

在方法中使用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)

于 2012-03-23T18:12:56.323 回答
5

“duck-typing”原则是你不关心是什么other,只要它有一个value属性。因此,除非您的属性与语义冲突的名称共享名称,否则我建议这样做:

def __eq__(self, other):
    try:
        return self.value == other.value
    except AttributeError:
        return False # or whatever

(或者你可以测试是否other有一个value属性,但是“请求宽恕比获得许可更容易”)

于 2012-03-23T17:28:49.857 回答