use*_*896 5 python inheritance metaclass python-2.x
奇怪的行为代码(用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__
Run Code Online (Sandbox Code Playgroud)
它的输出:
Declaring BaseClass1
Hello Meta1.__new__
-----------------------
Declaring BaseClass2
Hello Meta2.__new__
Hello Meta1.__new__ # WHY WAS IT INVOKED?
-----------------------
<class '__main__.Meta1'>
Run Code Online (Sandbox Code Playgroud)
关于代码的问题:
为什么定义类BaseClass2没有任何问题,即使__metaclass__
BaseClass2 的属性设置为Meta2,并且对于它的'父类BaseClass1 __metaclass__
属性设置为Meta1,并且Meta1没有Meta2是另一个类的子类?
为什么在BaseClass2定义都Meta2.__new__
与Meta1.__new__
被称为?
在哪种情况下调用父类的元类中的方法?
很长的故事:
在尝试理解我们项目中的元类如何工作时,我制作了上面可以找到的代码.(该项目使用Python 2.7.3,它看起来项目中使用的元类是合理的,因为它们用于向用户提供API,而元类为用户提供了很多东西.)
首先,我试图找到有关元类如何使用继承的文档.Guido van Rossum的以下(相当陈旧但看起来对Python 2.7有效)的文章阐明了在继承的情况下如何选择元类,对于subling类的元类有什么要求以及可以使用的小技巧在为兄弟类选择元类时由Python执行:https://www.python.org/download/releases/2.2.3/descrintro/.我在Python中使用元类读取的这些和其他着作并没有解释我观察到的行为.我想阅读Python解释器代码将揭示亮点,但我相信文档的力量,并希望可以避免这种极端的措施.任何描述所观察到的代码行为的材料的答案/指针都是受欢迎的.
经过大量环顾四周后,我想我找到了答案。Python 3文档中有一节说明了这一点。
\n\n\n\n\n3.3.3.3. 确定适当的元类
\n\n类定义的适当元类确定如下:
\n\n\n
\n\n- 如果没有给出基类和显式元类,则
\ntype()
使用then- 如果给出了显式元类并且它不是 的实例
\ntype()
,则\n 直接将其用作元类- 如果 的实例
\ntype()
作为显式元类给出,或者定义了基类,则使用最派生的元类最派生的元类是从显式指定的元类(如果有)和
\ntype(cls)
所有指定的基类的元类(即)中选择的。最派生的元类是所有这些候选元类的子类型。如果没有一个候选元类满足该标准,则类定义将失败并显示TypeError
。
我认为这仍然适用于 Python 2(无论如何 v2.7),尽管我在其文档中找不到类似上面的内容。
\n\nBaseClass2
该定义调用两者Meta2.__new__()
的 原因Meta1.__new__()
很简单 \xe2\x80\x94Meta2.__new__()
通过调用 来显式调用它super()
。然而,为了让它正常工作,您还需要进行更改Meta2.__new__()
,以便它返回super(Meta2, mcl).__new__(mcl, name, bases, attrs)
而不是super(Meta2, mcl).__new__(type, name, bases, attrs)
.
归档时间: |
|
查看次数: |
166 次 |
最近记录: |