Reputation: 143
There is no way to return False
from issubclass when class is derived from class with __subclashook__
implementation. I modified code from:
python subclasscheck & subclasshook
I only added '(Sized)' to both class definitions:
from abc import ABCMeta
class Sized(metaclass=ABCMeta):
@classmethod
def __subclasshook__(cls, C):
if cls is Sized:
if any("__len__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
class A(Sized):
pass
class B(Sized):
def __len__(self):
return 0
print(issubclass(A, Sized)) # True - should be False
print(issubclass(B, Sized)) # True
Is there any way to return False
in this case? Or maybe I'm doing something wrong?
Upvotes: 0
Views: 898
Reputation: 143
I think the good way to implement this:
from abc import ABCMeta
class Sized(metaclass=ABCMeta):
@classmethod
def __subclasshook__(cls, C):
if cls is Sized:
if any("__len__" in B.__dict__ for B in C.__mro__):
return True
else:
return False
return NotImplemented
class A(Sized):
pass
class B(Sized):
def __len__(self):
return 0
print(issubclass(A, Sized)) # False
print(issubclass(B, Sized)) # True
I think that when we assume that abc
is mechanism similar to compilation (or reflection) in other languages we should return False. If there is some doubt the class is correct subbclass then code shouldn't run or even compile (not in python).
Upvotes: 1
Reputation: 152677
The problem is that you return NotImplemented
when the __subclasshook__
doesn't exit early. And as stated in the documentation:
If it returns NotImplemented, the subclass check is continued with the usual mechanism.
So it uses the normal subclass check and finds that you do, in fact, inherit from Sized
so returns True
.
There are two solutions:
return False
instead of return NotImplemented
. However, do you really want/need issubclass
to return False
for direct subclasses?
If you inherit from object
for classes A
and B
it works as expected:
class A(object):
pass
class B(object):
def __len__(self):
return 0
print(issubclass(A, Sized)) # False
print(issubclass(B, Sized)) # True
Upvotes: 3