Why isinstance(Test(), MyAbstractClass) return False even if I implement all abstract methods in Test class

Question:

From some book, it says when we define a class and implement all abstract methods, even if the class is not inherited from abstract class, the isinstance() check will return True.
I try it on my local:

from collections import abc

class Test:
    def __len__(self):
        return 0

print(isinstance(Test(), abc.Sized))

Because there is only one abstract method in abc.Sized class:_len_, the output is True as expected.

But when I try to define my own abstract class, it fails:

from abc import abstractmethod, ABCMeta

Class MyAbstractClass(metaclass=ABCMeta):
    @abstractmethod
    def get_size(self):pass

class Test:
    def get_size(self):
        return 0

print(isinstance(Test(), MyAbstractClass))

The output is False. I need to register it if I want it to be True:

MyAbstractClass.register(Test)

Why? Why I check it with abs.Sized I don’t need to register it but with my own defined abstract class, I have to register it?

Asked By: Jared Zhu

||

Answers:

Test class should inherit MyAbstractClass.

from abc import abstractmethod, ABCMeta

class MyAbstractClass(metaclass=ABCMeta):
    @abstractmethod
    def get_size(self):pass

class Test(MyAbstractClass):
    def get_size(self):
        return 0

print(isinstance(Test(), MyAbstractClass))
Answered By: 吴慈霆

There is a way of getting Python to do the duck typing that you are looking for: anything that implements get_size is automatically an instance of your abstract class.

Many of pythons abstract base classes use this.

class MyAbstractClass(metaclass=ABCMeta):
    @classmethod
    def __subclasshook__(cls, C):
        if cls is MyAbstractClass:
            if any("get_size" in B.__dict__ for B in C.__mro__):
                return True
        return False
Answered By: Frank Yellin