Search code examples
pythonsubclasspython-2.xmetaclass

What's the usage of a virtual subclass?


class AnimalMeta(type):
    def __instancecheck__(cls, instance):
        return cls.__subclasscheck__(type(instance))

    def __subclasscheck__(cls, sub):
        return (hasattr(sub, 'eat') and callable(sub.eat) and
                hasattr(sub, 'sleep') and callable(sub.sleep))


class Animal(object):
    __metaclass__ = AnimalMeta
    pass


class Dog(object):
    def eat(self):
        print "eat"
    def sleep(self):
        print "sleep"


dog = Dog()
dog.eat()

print isinstance(dog, Animal)
print issubclass(dog, Animal)

Output:

eat
True
True

I am trying to understand python virtual subclass, example shows as above. instance a virtual subclass doesn't require implement abstract method at all.

What's the real use cases of virtual subclass? it seems to me the virtual subclass works like something in the middle of duck type and object inherit.

Duck type -- virtual subclass -- object inheritance


Solution

  • I read Interfaces in Python: Protocols and ABCs and it gives me a better understanding. We have duck typing in Python:

    If it talks and walks like a duck, then it is a duck.

    However, a Bird and Aeroplane both can fly(). But they are not the same thing. Hence, we need to define an interface to distinguish them from each other. (Python does not have an interface keyword, so we are actually using abstract classes)

    Let's me show an example:

    We have Duck and MyPlane in our program. Both of them implemented fly() method. Now we want to choose a plane from the hangar, get some people on board, and fly to another city. Apparently, we cannot put people onto a Duck, so we define an interface called (actually, an abstract class) Plane. And we let MyPlane to subclass Plane.

    Everything works fine. When we want to choose a plane, we check if it subclasses Plane. However, the Boeing company developed a package, which has a Boeing747Plane. We bought the plane (from boeing_airplanes import Boeing747Plane), but it is not recognized as a plane. It does have a fly() method, but it's not inherited from our Plane class so our Python interpreter won't recognize it as a plane.

    The good news is that Python is a flexible language. Thanks for register method of ABCMeta, after we do Plane.register(Boeing747Plane), Boeing747Plane is a subclass of Plane now. We can use third-party Boeing747Plane like our own built Plane. Hooray!

    So you see, virtual classes are used when we want to make a class from a third-party package to be a subclass of our own abstract class. We want it to implement our interface, but we cannot change its code, so we tell the interpreter explicitly "it implemented our interface, please treat it as the subclass of our own class". I think normally we wouldn't want to use it, but when you need to, use it cautiously. As Luca Cappelletti said, this is one of many flexibilities that Python allows for, following its philosophy of "we are adults here".