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 function? For example:
class Trout(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return isinstance(other, Trout) and self.value == other.value
You can use isinstance in Python to verify that the data you are working with is stored as the appropriate data type. When using Python, check data types as needed. isinstance() is a function built into Python that checks whether a value is stored as a particular data type.
Duck typing is a concept related to dynamic typing, where the type or the class of an object is less important than the methods it defines. When you use duck typing, you do not check types at all. Instead, you check for the presence of a given method or attribute.
Python isinstance() Function The isinstance() function returns True if the specified object is of the specified type, otherwise False . If the type parameter is a tuple, this function will return True if the object is one of the types in the tuple.
Duck Typing is a type system used in dynamic languages. For example, Python, Perl, Ruby, PHP, Javascript, etc. where the type or the class of an object is less important than the method it defines. Using Duck Typing, we do not check types at all.
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.
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With