子类的元类是如何确定的?
How is the metaclass of a subclass determined?
对于下面的代码:
class TestMeta(type):
def __init__(cls, classname, bases, dict_):
print(f'In TestMeta, class {cls}')
type.__init__(cls, classname, bases, dict_)
class Parent(metaclass=TestMeta):
pass
class Child(Parent, metaclass=type):
pass
输出为:
In TestMeta, class <class '__main__.Parent'>
In TestMeta, class <class '__main__.Child'>
在我看来,在创建 class Parent
时,TestMeta.__init__
会 运行,但为什么在创建 [=] 时又会 运行 27=] Child
我把它的 metaclass 改成了 type
?继承和传递metaclass
时metaclass如何确定?
来自 the docs:
The appropriate metaclass for a class definition is determined as
follows:
if no bases and no explicit metaclass are given, then type()
is used;
if an explicit metaclass is given and it is not an instance of type()
, then it is used directly as the metaclass;
if an instance of type()
is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used.
The most derived metaclass is selected from the explicitly specified
metaclass (if any) and the metaclasses (i.e. type(cls)
) of all
specified base classes. The most derived metaclass is one which is a
subtype of all of these candidate metaclasses.
在你上面的例子中,第三个项目符号成立,因为 type
作为显式元类给出并且有 base-classes.
根据最派生元类的定义,候选者为:TestMeta
和type
。由于TestMeta
继承了type
,是最派生的元类,确实是Child
的元类。
为了证明区别,下面的代码展示了我们如何 "force" Child
得到指定的 metaclass
而不是继承的:
class TestMeta(type):
def __init__(cls, classname, bases, dict_):
print(f'In TestMeta, class {cls}')
type.__init__(cls, classname, bases, dict_)
class OtherMeta(TestMeta):
def __init__(cls, classname, bases, dict_):
print(f'In OtherMeta, class {cls}')
type.__init__(cls, classname, bases, dict_)
class Parent(metaclass=TestMeta):
pass
class Child(Parent, metaclass=OtherMeta):
pass
输出将是:
In TestMeta, class <class '__main__.Parent'>
In OtherMeta, class <class '__main__.Child'>
再次注意,根据最派生元类的定义,这仅在 OtherMeta
本身是 TestMeta
的子类时有效。去掉这个继承关系会报错:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
对于下面的代码:
class TestMeta(type):
def __init__(cls, classname, bases, dict_):
print(f'In TestMeta, class {cls}')
type.__init__(cls, classname, bases, dict_)
class Parent(metaclass=TestMeta):
pass
class Child(Parent, metaclass=type):
pass
输出为:
In TestMeta, class <class '__main__.Parent'>
In TestMeta, class <class '__main__.Child'>
在我看来,在创建 class Parent
时,TestMeta.__init__
会 运行,但为什么在创建 [=] 时又会 运行 27=] Child
我把它的 metaclass 改成了 type
?继承和传递metaclass
时metaclass如何确定?
来自 the docs:
The appropriate metaclass for a class definition is determined as follows:
if no bases and no explicit metaclass are given, then
type()
is used;if an explicit metaclass is given and it is not an instance of
type()
, then it is used directly as the metaclass;if an instance of
type()
is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used.The most derived metaclass is selected from the explicitly specified metaclass (if any) and the metaclasses (i.e.
type(cls)
) of all specified base classes. The most derived metaclass is one which is a subtype of all of these candidate metaclasses.
在你上面的例子中,第三个项目符号成立,因为 type
作为显式元类给出并且有 base-classes.
根据最派生元类的定义,候选者为:TestMeta
和type
。由于TestMeta
继承了type
,是最派生的元类,确实是Child
的元类。
为了证明区别,下面的代码展示了我们如何 "force" Child
得到指定的 metaclass
而不是继承的:
class TestMeta(type):
def __init__(cls, classname, bases, dict_):
print(f'In TestMeta, class {cls}')
type.__init__(cls, classname, bases, dict_)
class OtherMeta(TestMeta):
def __init__(cls, classname, bases, dict_):
print(f'In OtherMeta, class {cls}')
type.__init__(cls, classname, bases, dict_)
class Parent(metaclass=TestMeta):
pass
class Child(Parent, metaclass=OtherMeta):
pass
输出将是:
In TestMeta, class <class '__main__.Parent'>
In OtherMeta, class <class '__main__.Child'>
再次注意,根据最派生元类的定义,这仅在 OtherMeta
本身是 TestMeta
的子类时有效。去掉这个继承关系会报错:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases