python虚拟子类的用途是什么?

时间:2018-08-03 05:57:01

标签: python

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)

eat
True
True

我试图理解python虚拟子类,示例如上所示。实例,虚拟子类根本不需要实现抽象方法。

虚拟子类的实际用例是什么?在我看来,虚拟子类的工作方式就像在鸭子类型和对象继承中间。

鸭子类型-虚拟子类-对象继承

2 个答案:

答案 0 :(得分:3)

我读了http://masnun.rocks/2017/04/15/interfaces-in-python-protocols-and-abcs/,它使我有了更好的理解。我们在Python中输入鸭子:

  

如果它说话像鸭子一样走路,那它就是鸭子。

但是,BirdAeroplane都可以fly()。但是他们不是同一回事。因此,我们需要定义一个接口来区分它们。 (Python没有interface关键字,因此我们实际上正在使用抽象类)

让我展示一个例子:

我们的程序中有DuckMyPlane。他们两个都实现了fly()方法。现在,我们想从机库中选择一架飞机,让一些人登机,然后飞往另一个城市。显然,我们无法将人们放在Duck上,因此我们定义了一个称为(实际上是抽象类)Plane的接口。然后让MyPlane继承Plane的子类。

一切正常。当我们想选择一个飞机时,我们检查它是否属于Plane的子类。但是,波音公司开发了一个带有Boeing747Plane的程序包。我们购买了飞机(from boeing-airplanes import Boeing747Plane,但未被识别为飞机。它确实具有fly()方法,但是它不是从我们的Plane类继承的,因此我们的Python解释器不会将其识别为飞机。

好消息是Python是一种灵活的语言。感谢register的{​​{1}}方法,在完成ABCMeta之后,Plane.register(Boeing747Plane)现在是Boeing747Plane的子类。我们可以像我们自己构建的Plane一样使用第三方Boeing747Plane。哇!

因此,您看到的是,当我们希望从第三方程序包中创建一个类作为我们自己的抽象类的子类时,将使用虚拟类。我们希望它实现我们的接口,但是不能更改其代码,因此我们明确告诉解释器“它实现了我们的接口,请将其视为我们自己类的子类”。我认为通常我们不想使用它,但是当您需要使用时,请谨慎使用。 正如Luca Cappelletti所说,这是Python遵循“我们在这里成年”的理念所允许的众多灵活性之一。

答案 1 :(得分:2)

为什么用抽象类扩展抽象类

假设您的项目要更复杂。您可以有抽象类,例如AnimalLandAnimalSeaAnimal,然后有具体类,例如DogWolfFish现在让我们忽略一些狗游泳和一些鱼走动):

Structure implementation

在这种实现中,“中间”的抽象类非常有用,因为它们同意避免重复代码,例如LandAnimal示例。

当然也可以使用装饰器而不是抽象方法move上的子类来实现此代码,但是通常当它们包装的代码很重要或至少会带来语义优势时,人们更喜欢抽象子类。 / p>

如何在python中实现

在python中,您可以通过向其添加一个在不被覆盖时引发异常的方法来创建抽象类,如:

class A:
    def my_abstract_method(self):
        raise NotImplementedError("You should override 'my_abstract_method'")

或者,在python“> 2.6”中,您可以使用ABC,该软件包基本上提供了创建抽象类所需的全部内容,例如装饰器和ABC(抽象基类):< / p>

from abs import ABS, abstractmethod

class A(ABC):
    @abstractmethod
    def my_abstract_method(self):
        pass