行为异常的代码(使用 Python 2.7.3 测试):
class Meta1(type):
def __new__(mcl, name, bases, attrs):
print "Hello Meta1.__new__ "
return super(Meta1, mcl).__new__(mcl, name, bases, attrs)
class Meta2(type):
def __new__(mcl, name, bases, attrs):
print "Hello Meta2.__new__ "
return super(Meta2, mcl).__new__(
type, # looks to cause all strange behavior, but anyway pass type here, not mcl
name, bases, attrs)
print "Declaring BaseClass1"
class BaseClass1(object):
__metaclass__ = Meta1
print "-----------------------"
print "Declaring BaseClass2"
class BaseClass2(BaseClass1):
__metaclass__ = Meta2
print "-----------------------"
print BaseClass2.__class__
它的输出:
Declaring BaseClass1
Hello Meta1.__new__
-----------------------
Declaring BaseClass2
Hello Meta2.__new__
Hello Meta1.__new__ # WHY WAS IT INVOKED?
-----------------------
<class '__main__.Meta1'>
关于代码的问题:
为什么类 BaseClass2 的定义没有任何问题,即使 BaseClass2 的 __metaclass__
属性设置为 Meta2 而其父类 BaseClass1 的 __metaclass__
属性设置为Meta1,Meta1 和 Meta2 都不是另一个类的子类吗?
为什么在 BaseClass2 定义中同时调用了 Meta2.__new__
和 Meta1.__new__
?
在什么情况下会调用父类的元类中的方法?
长话短说:
在尝试了解我们项目中的元类如何工作时,我编写了上面可以找到的代码。 (该项目使用 Python 2.7.3,看起来项目中使用的元类是合理的,因为它们用于向用户提供 API,并且元类在幕后为用户做了很多事情。)
首先,我试图找到有关元类如何与继承一起工作的文档。 Guido van Rossum 的以下文章(很旧但看起来对 Python 2.7 有效)阐明了在继承的情况下如何选择元类,子类的元类的要求是什么以及可以使用的小技巧在为兄弟类选择元类时由 Python 执行:https://www.python.org/download/releases/2.2.3/descrintro/ .我在 Python 中阅读的关于元类的这篇文章和其他文章并没有解释我观察到的行为。我想阅读 Python 解释器代码会有所启发,但我相信文档的力量,并希望可以避免这种极端措施。欢迎对描述观察到的代码行为的 Material 提供任何答案/指针。
最佳答案
经过大量的环顾四周,我想我找到了答案。 Python 3 文档有一个 section就是这么说的。
3.3.3.3. Determining the appropriate metaclass
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 usedThe 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. If none of the candidate metaclasses meets that criterion, then the class definition will fail withTypeError
.
我认为这仍然适用于 Python 2(无论如何都是 v2.7),尽管我在其文档中找不到类似上述内容的内容。
BaseClass2
定义同时调用 Meta2.__new__()
和 Meta1.__new__()
的原因很简单——Meta2.__new__()
通过调用 super()
显式调用它。但是,要让它正常工作,您还需要更改 Meta2.__new__()
以便它返回 super(Meta2, mcl).__new__(mcl, name, bases, attrs)
而不是 super(Meta2, mcl).__new__(type, name, bases, attrs)
。
关于python - 在什么情况下调用父类的多个元类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31946790/