Python默认元类

时间:2013-07-05 02:43:29

标签: python metaclass

是否有可能以某种方式配置python模块或REPL以对所有定义的类使用默认元类,而不管类中是否使用了元类?

class met(type):
    def __init__(cls, name, bases, dct):
        super(met, cls).__init__(name, bases, dct)
        setattr(cls, "_test_member", "test_value")

class A(object):
    pass

>>> A._test_member
'test_value'

2 个答案:

答案 0 :(得分:3)

使用Pavel Anossov(现已删除)评论:

class met(type):
    def __init__(cls, name, bases, dct):
        super(met, cls).__init__(name, bases, dct)
        cls._test_member = "test_value"

object = met('object', (object,), {})

class A(object):
    pass

print(A._test_member)

打印

test_value

请注意,一个类只能有一个元类。 (毕竟,任何对象都只能有一种类型)。但另外,类的元类必须是其所有基类的元类的(非严格)子类。换句话说,类的元类和其所有基类的元类必须相同,或者所有这些元类必须是彼此的子类。因此,如果类尝试使用不是met的子类的元类,则上述解决方案可能无效。

例如,

class met(type):
    def __init__(cls, name, bases, dct):
        super(met, cls).__init__(name, bases, dct)
        cls._test_member = "test_value"

object = met('object', (object,), {})

class someothertype(type): pass

class B(object):
    __metaclass__ = someothertype

加注

TypeError: Error when calling the metaclass bases
    metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

答案 1 :(得分:2)

在python 2.x上你可以做到

 __metaclass__ = met

在模块的开头,然后在旧样式模式下定义您的类:

class A:
    pass

在3.x上,这已不再可能。此外,“明确比隐含更好。”

另一种方法,你可以这样做:

class Object(metaclass=met):  # Py3k syntax
    pass

并且始终从中继承。

注意:调用type的子类是使用与Py2k和Py3k兼容的元类的唯一方法。就像unutbu的答案一样