Reputation: 403
I have implemented a class and its metaclass, both defining binary dunder methods including __eq__
and __hash__
. The metaclass' __eq__
method should simply instantiate the class and then pass the comparision to the class operator. But when I use isinstance
on my classes, I end up in an infinite recursion because isinstance
seems to be calling the metaclass' __eq__
method which in turn calls the class' __eq__
method which calls isinstance
again.
from abc import ABCMeta
class Metaclass(ABCMeta):
def __eq__(cls, other):
return cls() == other
def __hash__(cls):
return 0 #would be implemented accordingly with a correct hastype
class Myclass(metaclass=Metaclass):
def __eq__(self, other):
if isinstance(other, Myclass):
"""dostuff"""
else:
return NotImplemented
class Childclass(Myclass): pass
isinstance(Childclass, Myclass)
This is the result for me in python3.6.7:
[...]
File "./test.py", line 14, in __eq__
if isinstance(other, Myclass):
File "/usr/lib/python3.6/abc.py", line 193, in __instancecheck__
return cls.__subclasscheck__(subclass)
File "/usr/lib/python3.6/abc.py", line 218, in __subclasscheck__
if cls in getattr(subclass, '__mro__', ()):
File "./test.py", line 7, in __eq__
return cls() == other
File "./test.py", line 14, in __eq__
if isinstance(other, Myclass):
File "/usr/lib/python3.6/abc.py", line 193, in __instancecheck__
return cls.__subclasscheck__(subclass)
File "/usr/lib/python3.6/abc.py", line 218, in __subclasscheck__
if cls in getattr(subclass, '__mro__', ()):
File "./test.py", line 7, in __eq__
return cls() == other
File "./test.py", line 14, in __eq__
if isinstance(other, Myclass):
File "/usr/lib/python3.6/abc.py", line 193, in __instancecheck__
return cls.__subclasscheck__(subclass)
File "/usr/lib/python3.6/abc.py", line 218, in __subclasscheck__
if cls in getattr(subclass, '__mro__', ()):
File "./test.py", line 7, in __eq__
return cls() == other
RecursionError: maximum recursion depth exceeded while calling a Python object
Upvotes: 0
Views: 974
Reputation: 3555
isinstance(Childclass, Myclass)
Is never going to do what you think because isinstance
takes an instance of a class not the class itself.
And lo and behold, if you instantiate Childclass
, this call succeeds.
isinstance(Childclass(), Myclass) # => True
I've just run this, and I can't see an error. Running Python 3.7.5.
In [35]: from abc import ABCMeta
...:
...: class Metaclass(ABCMeta):
...: def __eq__(cls, other):
...: return cls() == other
...:
...: def __hash__(cls):
...: return 0 #would be implemented accordingly with a correct hastype
...:
...: class Myclass(metaclass=Metaclass):
...: def __eq__(self, other):
...: if isinstance(other, Myclass):
...: """dostuff"""
...: else:
...: return NotImplemented
...:
...: class Childclass(Myclass): pass
...:
In [36]: isinstance(Childclass, Myclass)
Out[36]: False
Upvotes: 1