为什么__metaclass__不起作用?

时间:2013-11-22 02:57:56

标签: python django

在阅读部分Django源代码后,我想在下面做一些测试和编写代码,看看元类是如何工作的:

class MyMeta(type):
    def __new__(cls, name, bases, attrs):
        print cls, name, bases, attrs
        return super(MyMeta, cls).__new__(cls, name, bases, attrs)

class AttrFiled(object): pass

class Test(MyMeta):
    name = AttrField()

总是抱怨:

TypeError: __new__() takes at least 2 arguments (1 given)

我添加修改如下:

def with_metaclass(meta, *bases):  # copied from Django code.
    return meta("NewBase", bases, {})

class Test(with_metaclass(MyMeta)):
    name = CharField()

它有效。

我也读过这个What is a metaclass in Python?。 但仍感到困惑。

提前致谢!

1 个答案:

答案 0 :(得分:4)

with_metaclass最初是在six库中引入的(如果我没记错的话),这简化了从Python 2到Python 3的过渡。这是一个聪明的技巧,使代码与它们兼容。 / p>

Python 2具有以下语法来声明使用元类:

class Foo(object):
    __metaclass__ = FooMeta

Python 3,有一个不同的:

class Foo(metaclass=FooMeta):
    pass

with_metaclass(meta)做了什么:它直接使用meta元类'构造函数创建一个中间临时类,并从中派生出类。所以Pythons - 2和3都很高兴。

您还应该阅读有关此主题的Python文档:http://docs.python.org/3/reference/datamodel.html#metaclasses


在您的具体情况下,当您撰写class Test(MyMeta):时,您只是声明一个源自Test元类 MyMeta。要制作,您需要编写

 class Test:
     __metaclass__ = MyMeta

 class Test(metaclass=MyMeta):
     ...

取决于你拥有的python版本。或者,如果您不确定是否需要支持Python 2,则只需使用with_metaclass,它也可以。