Python元类行为(不调用__new__),有解释吗?

时间:2015-02-11 22:40:10

标签: python python-2.7 metaclass

在名为exp.py(下面)的文件中,我试图理解Python中的元类。似乎当元类的__new__方法使用'type'构造函数构造一个类时,它的__new__方法不会被类的子类调用,而是使用它作为元类:

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>}
>>> 

正如您所看到的,当加载类F的定义时,不会调用元类D的__new__方法。 (如果已经调用过,那么关于F类的信息也会打印出来。)

有人可以帮我解释一下吗?


相关文章:我正在阅读What is a metaclass in Python?,似乎在句子中遇到类似的内容,“请注意,__metaclass__属性不会被继承,父类的元类({{如果Bar使用Bar.__class__属性创建Bar __metaclass__(而不是type()),那么子类将不会继承该行为。“但我并不完全理解这一点。

1 个答案:

答案 0 :(得分:3)

在第二种情况下,不是返回元类的实例而是实际返回type的实例,而是依次设置新创建的类{{1}的__class__属性而E代替<type 'type'>。因此,as per the rule 2 Python检查基类的D属性(或__class__type(E))并决定使用E.__class__作为type该元类,因此在这种情况下永远不会调用F&#39; s D

  • 如果__new__存在,则使用它。
  • 否则,如果至少有一个基类,则使用其元类(这首先查找dict['__metaclass__']属性,如果未找到,则使用其类型)。

因此,正确的方法是在元类的__class__方法中调用类型__new__方法:

__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