起因经过
今天翻collections.abc的文档时,我知道list的实例在逻辑上(因为duck typing 鸭子类型)是Container和不能hash的(因为list可变),就试下面的代码是否能行:
from collections.abc import Container, Hashable
print(isinstance(list(), Container)) # return true
print(isinstance(list(), Hashable)) # return False
我就产生疑惑,问题1来了:list是继承于object, 而collections.abc.Container是个抽象类,isinstance为什么能正确运行?换另外一句话说,此时我的理解是根据isintance的语义来的,list并没有继承这个抽象类,why isintance() works?
class list(object):
...
class Container(metaclass=ABCMeta):
...
解决
查找isinstance()文档:
Return true if the object argument is an instance of the classinfo argument, or of a (direct, indirect or virtual) subclass thereof.
问题2来了,什么是virutal subclass? 刚好virutal那里有个超链接,点进去
Abstract base classes complement duck-typing by providing a way to define interfaces .... ABCs introduce virtual subclasses, which are classes that don’t inherit from a class but are still recognized by isinstance() and issubclass();
总结
豁然开朗,想起了以前读的Fluent Python,因为Python没有interface,抽象类实现了接口,补充了鸭子类型,加上isinstance支持判断抽象类,所以就可以判断。
isinstance支持direct(直接继承), indirect(非直接继承), virtual(抽象类)。以前对于isinstance的理解只局限在前两种。