What is metaclass in python

what is a metaclass in python - from stackoverflow

what is metaclass in python

metaclass 是一个 classclass, 就像一个类定义了它实例的行为, metaclass 定义了一个类的行为. 类是 metaclass 的实例.

在Python里, 你可以使用任意可调用的 metaclass, 更有用的实际上是使它成为一个类本身。 通常在Python中 type 就是一个 metaclass。 也许你会感到疑惑, type 就是一个类本身, 而且是它本身的类型。 在Python里, 你完全不需要重新创建 type, 因为Python已经做了。 在 Python中你真正想创建的是 type 的子类。

一个 metaclass 通常是用来作为一个类工厂。 就像你通过调用类创建实例一样, Python通过调用 metaclass 创建一个新的类(当它执行 class 语句的时候)。 结合 __init____new__ 方法, 当你创建一个类的时候,metaclass 允许你做一些 额外 的事情, 比如注册一个类,甚至替换这个类。

class 语句执行的时候, Python首先将类语句作为一个正常的代码块来执行, 然后类的namespace(一个字典)保存了这个类的属性。 metaclass 是通过类的 __metaclass__ 或者 __metaclass__ 全局变量来决定的(metaclasses 是通过继承得到的)。 然后通过类的name basesattributes 来调用 metaclass 来创建这个实例。

然而, metaclasses 实际上定义了一个类的类型, 而不是一个类工厂, 所以你可以用它做更多的事情。 你可以在 metaclass 为实例定义一些方法。 这些 metaclass-methods 就像 classmethods, 可以不需要实例直接通过类调用, 但是它们不能像 classmethods 一样通过类的实例来调用。 type.__subclasses__() 是一个 metaclass 的示例方法。 你也可以定义一些魔法方法, 比如 __add____iter____getattr__, 来实现或改变类的行为。

这里有一个例子:


def make_hook(f):
"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook = 1
return f

class MyType(type):
    def __new__(cls, name, bases, attrs):

        if name.startswith('None'):
            return None

        # Go over attributes and see if they should be renamed.
        newattrs = {}
        for attrname, attrvalue in attrs.iteritems():
            if getattr(attrvalue, 'is_hook', 0):
                newattrs['__%s__' % attrname] = attrvalue
            else:
                newattrs[attrname] = attrvalue

        return super(MyType, cls).__new__(cls, name, bases, newattrs)

    def __init__(self, name, bases, attrs):
        super(MyType, self).__init__(name, bases, attrs)

        # classregistry.register(self, self.interfaces)
        print "Would register class %s now." % self

    def __add__(self, other):
        class AutoClass(self, other):
            pass
        return AutoClass
        # Alternatively, to autogenerate the classname as well as the class:
        # return type(self.__name__ + other.__name__, (self, other), {})

    def unregister(self):
        # classregistry.unregister(self)
        print "Would unregister class %s now." % self

class MyObject:
    __metaclass__ = MyType


class NoneSample(MyObject):
    pass

# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)

class Example(MyObject):
    def __init__(self, value):
        self.value = value
    @make_hook
    def add(self, other):
        return self.__class__(self.value + other.value)

# Will unregister the class
Example.unregister()

inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()

print inst + inst
class Sibling(MyObject):
    pass

ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__