在CPython中以下
import collections
issubclass(dict, collections.Mapping)
返回True
。这让我感到困惑,因为dict
是CTypes中定义的内置类,而collections模块明确依赖于dict
的存在来完成它的一些功能。除了直接的继承检查之外的东西必须继续进行,我无法弄清楚为什么这样做。下面我提供一些导致我混淆的推理。
如果我们查看collections.Mapping
的继承结构,我们会看到它继承自Collection
。 Collection
's signature表明它继承自Sized
,Iterable
,Container
,所有这些都只从元类ABCmeta
继承。
但是dict
是一个内置的,我认为这意味着它被直接定义为一个CType,我认为这意味着它不会从任何东西继承。
那么,为什么issubclass(dict, collections.Mapping)
→True
?
有关其原因的更多背景请参阅this nbformat issue,其中尝试重新创建签名& dict
update
的功能我们需要了解issubclass(foo, Mapping)
的行为方式。
答案 0 :(得分:4)
MutableMapping.register(dict)
明确register
编辑MutableMapping
,abc.ABCMeta
定义issubclass
检查,以便将注册的类视为isinstance
的子类}和issubclass
使用__instancecheck__
和__subclasscheck__
挂钩进行检查。
答案 1 :(得分:3)
这是因为元类可以自定义issubclass
和isinstance
返回的内容。如果是MutableMapping
,则可以通过abc.ABCMeta
完成,这允许register"虚拟子类"。
例如:
from collections import MutableMapping
class A(object): pass
MutableMapping.register(A)
issubclass(A, MutableMapping) # True
它甚至适用于已注册子类的子类:
class B(object): pass
class C(B): pass
MutableMapping.register(B)
issubclass(C, MutableMapping) # True
dict
也是如此。因此即使它不是MutableMapping
的真正子类,它仍然是一个虚拟子类。就像第二个例子所示,这意味着所有"真实" dict
的子类也将是"虚拟" MutableMapping
的子类。
请注意,即使是更简单的ABCs也会根据方法的存在来实现子类检查。例如collections.Sized
checks if the class has a __len__
:
from collections import Sized
class D(object):
def __len__(self):
return 1
issubclass(D, Sized) # True
即使没有明确的register
,这个D
也会被视为Sized
的有效子类。