一般情况下,如果要用类来实现metaclass的话,该类需要继承与 type ,而且通常会重写 type 的 __new__方法老控制创建过程。在metaclass里面定义的方法会成为类的方法,可以直接通过类名来调用。
用类的形式:
类继承于 type, 例如 class Meta(type): pass
将需要使用metaclass来构建的类的__metaclass__属性赋值为 Meta。
metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了 type 的 __new__ 方法为这个类分配内存空间。创建好了之后再调用 type 的 __init__ 方法初始化。
__new__(cls, name, bases, attrs)
所以在创建类的过程,我们可以在这个函数里面修改name, bases, attrs的值来自由的达到我们的功能。
#!/usr/bin/python #coding :utf-8 def ma(cls): print 'method a' def mb(cls): print 'method b' method_dict = { 'ma': ma, 'mb': mb, } class DynamicMethod(type): def __new__(cls, name, bases, dct): if name[:3] == 'Abc': dct.update(method_dict) return type.__new__(cls, name, bases, dct) def __init__(cls, name, bases, dct): super(DynamicMethod, cls).__init__(name, bases, dct) class AbcTest(object): __metaclass__ = DynamicMethod def mc(self, x): print x * 3 class NotAbc(object): __metaclass__ = DynamicMethod def md(self, x): print x * 3 def main(): a = AbcTest() a.mc(3) a.ma() print dir(a) b = NotAbc() print dir(b) if __name__ == '__main__': main()
通过metaclass这个元类,可以在那些指定了__metaclass__属性的类里面,根据类名字,如果是以Abc开头的就给它们加上ma和mb方法。
只要我们能操作__new__方法里面的其中一个参数attrs,就可以动态添加东西了。
比如需要验证登陆或者是否有权限的,只有通过验证通过之后才可以操作,那么如果有很多个操作都需要这样做,我们一般情况下可以手动在每个方法的前头用@login_required类似这样的方法。如果使用了metaclass的使用的话,可以这样做:
#!/usr/bin/python #coding :utf-8 from types import FunctionType def login_required(func): print 'login check logic here' return func class LoginDecorator(type): def __new__(cls, name, bases, dct): for name, value in dct.iteritems(): if name not in ('__metaclass__', '__init__', '__module__') and\ type(value) == FunctionType: value = login_required(value) dct[name] = value return type.__new__(cls, name, bases, dct) class Operation(object): __metaclass__ = LoginDecorator def delete(self, x): print 'deleted %s' % str(x) def main(): op = Operation() op.delete('test') if __name__ == '__main__': main()
这样就可以不用在delete函数上面写@login_required,也能达到decrator的效果了。