自动继承collections.Callable(及其他类)是如何工作的?

0 投票
1 回答
1328 浏览
提问于 2025-04-18 13:37

这个问题主要是关于Python 2的,不过我也想知道在Python 3中是否有区别。

我发现,当在类中创建某些方法时(不管这些类是新式类还是旧式类),Python会自动认为这些类是来自collections模块的一些类。下面的例子展示了这一点,特别是关于collections.Callable。

>>> import collections
>>> class A:
        def __call__(self):
                print "A"


>>> a = A()
>>> isinstance(a, collections.Callable)
True
>>> class A(object):
        def __call__(self):
                print "A"


>>> a = A()
>>> isinstance(a, collections.Callable)
True
>>> class A(object):
        pass

>>> a = A()
>>> isinstance(a, collections.Callable)
False
>>> class A:
        pass

>>> a = A()
>>> isinstance(a, collections.Callable)
False

你会注意到,我并没有明确让这些类继承collections.Callable,但只要它们创建了一个__call__方法,Python就会自动把它们当作是这个类的实例。这是出于某种特定的目的吗?这个规则在某个地方有明确的说明吗?Python是不是在自动给类分配某些基类,仅仅因为定义了方法,还是说还有其他原因呢?

对于collections.Iterable和__iter__方法,以及其他一些特殊方法,你也会得到类似的结果。

1 个回答

0

ABCMeta 类是用来定制实例和子类检查的工具,它提供了两个方法:__instancecheck__()__subclasscheck__()

这些工具会调用 ABCMeta.__subclasshook__() 方法来进行具体的检查:

__subclasshook__(subclass)

这个方法用来检查 subclass 是否被认为是这个抽象基类(ABC)的子类。也就是说,你可以进一步定制 issubclass 的行为,而不需要在每个你想要认为是 ABC 子类的类上都调用 register()

这个工具可以检查给定的子类是否实现了预期的方法;对于 Callable 类来说,检查的方式很简单,只需要看看是否有 __call__ 方法:

@classmethod
def __subclasshook__(cls, C):
    if cls is Callable:
        if _hasattr(C, "__call__"):
            return True
    return NotImplemented

这个检查是专门针对 Callable 类的;如果你创建了子类,就需要自己实现相应的版本,因为你很可能会添加新的方法。

撰写回答