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 虚拟子类,示例如上所示。实例一个虚拟子类根本不需要实现抽象方法。
虚拟子类的真正用例是什么?在我看来,虚拟子类就像鸭子类型和对象继承中间的东西。
鸭子类型——虚拟子类——对象继承
解决方案
我阅读了 Python 中的接口:协议和 ABC,它让我有了更好的理解。我们在 Python 中有鸭子类型:
如果它说话和走路都像鸭子,那么它就是鸭子。
但是,aBird
和Aeroplane
两者都可以fly()
。但它们不是一回事。因此,我们需要定义一个接口来区分它们。(Python没有interface
关键字,所以我们实际上是在使用抽象类)
让我举个例子:
我们有Duck
并且MyPlane
在我们的计划中。他们都实现了fly()
方法。现在我们想从机库中选择一架飞机,让一些人登机,然后飞往另一个城市。显然,我们不能把人放在 a 上Duck
,所以我们定义了一个名为(实际上是一个抽象类)的接口Plane
。我们让MyPlane
子类化Plane
。
一切正常。当我们想选择一个平面时,我们检查它是否是子类Plane
。然而,波音公司开发了一个包,它有一个Boeing747Plane
. 我们买了飞机 ( from boeing-airplanes import Boeing747Plane
),但它不被识别为飞机。它确实有一个fly()
方法,但它不是从我们的类继承的,Plane
所以我们的 Python 解释器不会将它识别为平面。
好消息是 Python 是一种灵活的语言。感谢register
方法 of ABCMeta
,在我们做之后Plane.register(Boeing747Plane)
,Boeing747Plane
是Plane
now 的一个子类。Boeing747Plane
我们可以像我们自己构建的那样使用第三方Plane
。万岁!
所以你看,当我们想从第三方包中创建一个类成为我们自己抽象类的子类时,就会使用虚拟类。我们希望它实现我们的接口,但我们不能更改它的代码,所以我们明确告诉解释器“它实现了我们的接口,请把它当作我们自己类的子类”。我认为通常我们不想使用它,但是当您需要时,请谨慎使用它。正如 Luca Cappelletti 所说,这是 Python 允许的众多灵活性之一,遵循其“我们在这里是成年人”的理念。
推荐阅读
- javascript - 如何知道在分组堆叠条(chartjs)中单击了哪个堆栈?
- java - 观察java中的实时数据列表
- lua - 如何更改 Lua 脚本中的文本颜色?
- javascript - 如何在不先下载每个分辨率的情况下获取每个分辨率的文件大小 ytdl-core
- python - 对于 python 中的以下代码,我收到错误--AttributeError: 'str' object has no attribute 'next'
- sonarlint-eclipse - 如何检查 SonarLint 插件是否真的在 Eclipse 中分析我的代码?
- python - 根据python中列的条件更新行值
- javascript - 在另一个 JavaScript 文件中扩展 JavaScript 类时遇到问题 - GULP
- c++ - 是否可以在一行中找到 C++ 中 3 个集合的交集?
- python - 如何在两个单独的脚本中导入共享变量?