虚子类有什么用?
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)
输出:
eat
True
True
我正在尝试理解 python 虚拟子类,示例如上所示。实例虚拟子类根本不需要实现抽象方法。
虚子类的实际用例是什么?在我看来,虚拟子类的工作方式类似于鸭子类型和对象继承之间的东西。
Duck类型--虚子类--对象继承
我读了 Interfaces in Python: Protocols and ABCs 它让我有了更好的理解。我们有鸭子输入 Python:
If it talks and walks like a duck, then it is a duck.
但是,Bird
和 Aeroplane
都可以 fly()
。但它们不是一回事。因此,我们需要定义一个接口来区分它们。 (Python 没有 interface
关键字,所以我们实际上使用的是抽象 classes)
让我举个例子:
我们的程序中有 Duck
和 MyPlane
。他们都实现了 fly()
方法。现在我们要从机库中选择一架飞机,让一些人登机,飞往另一个城市。显然,我们不能把人放到一个Duck
上,所以我们定义了一个接口叫做(实际上是一个抽象的class)Plane
。而我们让MyPlane
subclass Plane
.
一切正常。当我们要选择一个平面时,我们检查它是否 subclasses Plane
。然而,波音公司开发了一个包,其中有一个Boeing747Plane
。我们买了飞机(from boeing_airplanes import Boeing747Plane
),但它不被识别为飞机。它确实有一个 fly()
方法,但它不是从我们的 Plane
class 继承的,所以我们的 Python 解释器不会将它识别为一个平面。
好消息是 Python 是一种灵活的语言。感谢 ABCMeta
的 register
方法,在我们执行 Plane.register(Boeing747Plane)
之后,Boeing747Plane
现在是 Plane
的子 class。我们可以像自己构建的Plane
一样使用第三方Boeing747Plane
。万岁!
所以你看,虚拟 class 当我们想从第三方包中制作一个 class 成为我们自己的抽象 [=] 的子class 时使用54=]。我们希望它实现我们的接口,但是我们不能改变它的代码,所以我们明确地告诉解释器“它实现了我们的接口,请把它当作我们自己的class的subclass”。我认为通常我们不想使用它,但是当您需要时,请谨慎使用它。
正如 Luca Cappelletti 所说,这是 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 虚拟子类,示例如上所示。实例虚拟子类根本不需要实现抽象方法。
虚子类的实际用例是什么?在我看来,虚拟子类的工作方式类似于鸭子类型和对象继承之间的东西。
Duck类型--虚子类--对象继承
我读了 Interfaces in Python: Protocols and ABCs 它让我有了更好的理解。我们有鸭子输入 Python:
If it talks and walks like a duck, then it is a duck.
但是,Bird
和 Aeroplane
都可以 fly()
。但它们不是一回事。因此,我们需要定义一个接口来区分它们。 (Python 没有 interface
关键字,所以我们实际上使用的是抽象 classes)
让我举个例子:
我们的程序中有 Duck
和 MyPlane
。他们都实现了 fly()
方法。现在我们要从机库中选择一架飞机,让一些人登机,飞往另一个城市。显然,我们不能把人放到一个Duck
上,所以我们定义了一个接口叫做(实际上是一个抽象的class)Plane
。而我们让MyPlane
subclass Plane
.
一切正常。当我们要选择一个平面时,我们检查它是否 subclasses Plane
。然而,波音公司开发了一个包,其中有一个Boeing747Plane
。我们买了飞机(from boeing_airplanes import Boeing747Plane
),但它不被识别为飞机。它确实有一个 fly()
方法,但它不是从我们的 Plane
class 继承的,所以我们的 Python 解释器不会将它识别为一个平面。
好消息是 Python 是一种灵活的语言。感谢 ABCMeta
的 register
方法,在我们执行 Plane.register(Boeing747Plane)
之后,Boeing747Plane
现在是 Plane
的子 class。我们可以像自己构建的Plane
一样使用第三方Boeing747Plane
。万岁!
所以你看,虚拟 class 当我们想从第三方包中制作一个 class 成为我们自己的抽象 [=] 的子class 时使用54=]。我们希望它实现我们的接口,但是我们不能改变它的代码,所以我们明确地告诉解释器“它实现了我们的接口,请把它当作我们自己的class的subclass”。我认为通常我们不想使用它,但是当您需要时,请谨慎使用它。 正如 Luca Cappelletti 所说,这是 Python 允许的众多灵活性之一,遵循其“我们在这里是成年人”的理念。