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

Noe*_*ans 17 python duck-typing equality

你有一个需要等于测试的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
Run Code Online (Sandbox Code Playgroud)

amc*_*abb 14

__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
Run Code Online (Sandbox Code Playgroud)

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


Sve*_*ach 6

使用isintsance()方法通常很好__eq__().但是,False如果isinstance()检查失败,则不应立即返回- 最好返回NotImplemented以给予other.__eq__() 执行机会:

def __eq__(self, other):
    if isinstance(other, Trout):
        return self.x == other.x
    return NotImplemented
Run Code Online (Sandbox Code Playgroud)

这将在多个类定义的类层次结构中变得特别重要__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
Run Code Online (Sandbox Code Playgroud)

如果您False立即返回,就像在原始代码中那样,您将失去A(3) == B(3, 4)和之间的对称性B(3, 4) == A(3).


ale*_*xis 5

“鸭子类型”原则是,你不在乎它是什么other,只要它有一个value属性即可。因此,除非您的属性共享具有冲突语义的名称,否则我建议这样做:

def __eq__(self, other):
    try:
        return self.value == other.value
    except AttributeError:
        return False # or whatever
Run Code Online (Sandbox Code Playgroud)

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

  • 这可能会导致一些非常愚蠢的结果,比如 `Trout("rainbow") == Lorikeet("rainbow")`,尽管几乎没有人会认为鱼等于鸟。 (3认同)