Python 元类行为(不调用 __new__),有解释吗?
Python metaclass behavior (not calling __new__), is there an explanation?
在名为 exp.py 的文件(下)中,我试图理解 Python 中的元 classes。似乎当 metaclass 的 __new__
方法使用 'type' 构造函数构造 class 时,它的 __new__
方法不会被子调用class 的 class 使用它作为 metaclass:
class A(type):
def __new__(cls, name, bases, dct):
print "cls is: ", cls
print "name is: ", name
print "bases is: ", bases
print "dct is: ", dct
print
return super(A, cls).__new__(cls, name, bases, dct)
class B(object):
__metaclass__ = A
class C(B): pass
class D(type):
def __new__(cls, name, bases, dct):
print "cls is: ", cls
print "name is: ", name
print "bases is: ", bases
print "dct is: ", dct
return type(name, bases, dct)
class E(object):
__metaclass__ = D
class F(E): pass
在终端中:
>>> from exp import *
cls is: <class 'exp.A'>
name is: B
bases is: (<type 'object'>,)
dct is: {'count': 0, '__module__': 'exp', '__metaclass__': <class 'exp.A'>, '__init__': <function __init__ at 0x107eb9578>}
cls is: <class 'exp.A'>
name is: C
bases is: (<class 'exp.B'>,)
dct is: {'__module__': 'exp'}
cls is: <class 'exp.D'>
name is: E
bases is: (<type 'object'>,)
dct is: {'count': 0, '__module__': 'exp', '__metaclass__': <class 'exp.D'>, '__init__': <function __init__ at 0x107ebdb18>}
>>>
如您所见,加载 class F 的定义时,元 class D 的 __new__
方法不会被调用。 (如果它被调用,那么关于 class F 的信息也会被打印出来。)
谁能帮我解释一下?
相关post:我在看What is a metaclass in Python?,好像在句子中遇到了类似的东西,"Be careful here that the __metaclass__
attribute will not be inherited, the metaclass of the parent (Bar.__class__
) will be. If Bar used a __metaclass__
attribute that created Bar with type()
(and not type.__new__()
), the subclasses will not inherit that behavior."但是我没有完全理解这个。
在第二种情况下,您实际上返回的不是元 class 的实例,而是 type
的实例,这反过来又设置了新的 __class__
属性将 class E
创建为 <type 'type'>
而不是 D
。因此 as per the rule 2 Python 检查基础 class 的 __class__
属性(或 type(E)
或 E.__class__
)并决定使用 type
作为 F
的元 class,因此在这种情况下永远不会调用 D
的 __new__
。
- 如果
dict['__metaclass__']
存在,则使用它。
- 否则,如果至少有一个基class,则使用其元class(这会查找
__class__
属性首先,如果未找到,则使用其类型)。
所以,正确的方法是在metaclass的__new__
方法中调用type的__new__
方法:
class D(type):
def __new__(cls, name, bases, dct):
print "cls is: ", cls
print "name is: ", name
print "bases is: ", bases
print "dct is: ", dct
return type.__new__(cls, name, bases, dct)
class E(object):
__metaclass__ = D
class F(E): pass
class A(object):
pass
输出:
cls is: <class '__main__.D'>
name is: E
bases is: (<type 'object'>,)
dct is: {'__module__': '__main__', '__metaclass__': <class '__main__.D'>}
cls is: <class '__main__.D'>
name is: F
bases is: (<class '__main__.E'>,)
dct is: {'__module__': '__main__'}
在名为 exp.py 的文件(下)中,我试图理解 Python 中的元 classes。似乎当 metaclass 的 __new__
方法使用 'type' 构造函数构造 class 时,它的 __new__
方法不会被子调用class 的 class 使用它作为 metaclass:
class A(type):
def __new__(cls, name, bases, dct):
print "cls is: ", cls
print "name is: ", name
print "bases is: ", bases
print "dct is: ", dct
print
return super(A, cls).__new__(cls, name, bases, dct)
class B(object):
__metaclass__ = A
class C(B): pass
class D(type):
def __new__(cls, name, bases, dct):
print "cls is: ", cls
print "name is: ", name
print "bases is: ", bases
print "dct is: ", dct
return type(name, bases, dct)
class E(object):
__metaclass__ = D
class F(E): pass
在终端中:
>>> from exp import *
cls is: <class 'exp.A'>
name is: B
bases is: (<type 'object'>,)
dct is: {'count': 0, '__module__': 'exp', '__metaclass__': <class 'exp.A'>, '__init__': <function __init__ at 0x107eb9578>}
cls is: <class 'exp.A'>
name is: C
bases is: (<class 'exp.B'>,)
dct is: {'__module__': 'exp'}
cls is: <class 'exp.D'>
name is: E
bases is: (<type 'object'>,)
dct is: {'count': 0, '__module__': 'exp', '__metaclass__': <class 'exp.D'>, '__init__': <function __init__ at 0x107ebdb18>}
>>>
如您所见,加载 class F 的定义时,元 class D 的 __new__
方法不会被调用。 (如果它被调用,那么关于 class F 的信息也会被打印出来。)
谁能帮我解释一下?
相关post:我在看What is a metaclass in Python?,好像在句子中遇到了类似的东西,"Be careful here that the __metaclass__
attribute will not be inherited, the metaclass of the parent (Bar.__class__
) will be. If Bar used a __metaclass__
attribute that created Bar with type()
(and not type.__new__()
), the subclasses will not inherit that behavior."但是我没有完全理解这个。
在第二种情况下,您实际上返回的不是元 class 的实例,而是 type
的实例,这反过来又设置了新的 __class__
属性将 class E
创建为 <type 'type'>
而不是 D
。因此 as per the rule 2 Python 检查基础 class 的 __class__
属性(或 type(E)
或 E.__class__
)并决定使用 type
作为 F
的元 class,因此在这种情况下永远不会调用 D
的 __new__
。
- 如果
dict['__metaclass__']
存在,则使用它。 - 否则,如果至少有一个基class,则使用其元class(这会查找
__class__
属性首先,如果未找到,则使用其类型)。
所以,正确的方法是在metaclass的__new__
方法中调用type的__new__
方法:
class D(type):
def __new__(cls, name, bases, dct):
print "cls is: ", cls
print "name is: ", name
print "bases is: ", bases
print "dct is: ", dct
return type.__new__(cls, name, bases, dct)
class E(object):
__metaclass__ = D
class F(E): pass
class A(object):
pass
输出:
cls is: <class '__main__.D'>
name is: E
bases is: (<type 'object'>,)
dct is: {'__module__': '__main__', '__metaclass__': <class '__main__.D'>}
cls is: <class '__main__.D'>
name is: F
bases is: (<class '__main__.E'>,)
dct is: {'__module__': '__main__'}