Python 基类可以是没有 __mro_entries__ 的对象

Yur*_*bas 4 python python-3.x

今天我发现python对象没有__mro_entries__可以用作基类。

例子:

class Base:
    def __init__(self, *args):
        self.args = args

    def __repr__(self):
        return f'{type(self).__name__}(*{self.args!r})'


class Delivered(Base):
    pass


b = Base()
d = Delivered()


class Foo(b, d):
    pass


print(type(Foo) is Delivered)
print(Foo)
Run Code Online (Sandbox Code Playgroud)
True
Delivered(*('Foo', (Base(*()), Delivered(*())), {'__module__': '__main__', '__qualname__': 'Foo'}))
Run Code Online (Sandbox Code Playgroud)

结果Foo将是类的实例Delivered,并且它不是有效的类型。

我确实理解以下用例,__mro_entries__但是使用对象而不__mro_entries__作为基类的用例是什么。这是Python的一个错误吗?

che*_*ner 5

TL;DR 不是错误,而是对该class语句的极端滥用。


一条class语句相当于对元类的调用。由于缺乏显式metaclass关键字参数,元类必须从基类推断。这里,“类”的“元类”bBase,而 的元类dDelivered。由于每个元类都是公共元类 ( ) 的非严格子类BaseDelivered因此被选为更具体的元类。

>>> Delivered('Foo', (b, d), {})
Delivered(*('Foo', (Base(*()), Delivered(*())), {}))
Run Code Online (Sandbox Code Playgroud)

Delivered可以用作元类,因为它接受该class语句期望元类接受的相同参数:类型名称的字符串、父类的序列以及用作命名空间的映射。在这种情况下,Delivered不使用它们来创建类型;它只是打印参数。

因此,Foo绑定到 的实例Delivered,而不是类型。类也是如此Foo,只是在它是由语句生成的意义上class:它绝对不是类型。

>>> issubclass(Foo, Delivered)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 1 must be a class
>>> Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Delivered' object is not callable
Run Code Online (Sandbox Code Playgroud)