If duck-typing in Python, should you test isinstance?

前端 未结 3 1370
挽巷
挽巷 2021-02-04 05:01

You have a Python class which needs an equals test. Python should use duck-typing but is it (better/more accurate) to include or exclude an isinstance test in the eq

相关标签:
3条回答
  • 2021-02-04 05:32

    The "duck-typing" principle is that you don't care what other is, as long as it has a value attribute. So unless your attributes share names with conflicting semantics, I'd suggest doing it like this:

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

    (Alternately you could test whether other has a value attribute, but "it's easier to ask forgiveness than to get permission")

    0 讨论(0)
  • 2021-02-04 05:45

    Using isintsance() is usually fine in __eq__() methods. You shouldn't return False immediately if the isinstance() check fails, though -- it is better to return NotImplemented to give other.__eq__() a chance of being executed:

    def __eq__(self, other):
        if isinstance(other, Trout):
            return self.x == other.x
        return NotImplemented
    

    This will become particularly important in class hierarchies where more than one class defines __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
    

    If you would return False immediately, as you did in your original code, you would lose symmetry between A(3) == B(3, 4) and B(3, 4) == A(3).

    0 讨论(0)
  • 2021-02-04 05:47

    Using isinstance in __eq__ methods is pretty common. The reason for this is that if the __eq__ method fails, it can fallback on an __eq__ method from another object. Most normal methods are called explicitly, but __eq__ is called implicitly, so it requires look-before-you-leap more frequently.

    EDIT (thanks for the reminder, Sven Marnach):

    To make it fallback, you can return the NotImplemented singleton, as in this example:

    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
    

    Suppose a RainbowTrout knows how to compare itself to a Trout or to another RainbowTrout, but a Trout only knows how to compare itself to a Trout. In this example, if you test mytrout == myrainbowtrout, Python will first call mytrout.__eq__(myrainbowtrout), notice that it fails, and then call myrainbowtrout.__eq__(mytrout), which succeeds.

    0 讨论(0)
提交回复
热议问题