【Python基础】Python面向对象 - 8 - 元类2

metaclass基础

一般情况下,如果要用类来实现metaclass的话,该类需要继承与 type ,而且通常会重写 type 的 __new__方法老控制创建过程。在metaclass里面定义的方法会成为类的方法,可以直接通过类名来调用。


如何使用metaclass

用类的形式:

类继承于 type, 例如 class Meta(type): pass

将需要使用metaclass来构建的类的__metaclass__属性赋值为 Meta。


metaclass原理

metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了 type 的 __new__ 方法为这个类分配内存空间。创建好了之后再调用 type 的 __init__ 方法初始化。

__new__方法

__new__(cls, name, bases, attrs)

  • cls: 将要创建的类,类似于self,但是self指向的是Instance,而这里cls指向的是class
  • name: 类的名字,也就是我们通常用类名__name__获取的
  • base: 基类
  • attrs: 属性的dict,dict的内容可以是变量(类属性),也可以是函数(类方法)

所以在创建类的过程,我们可以在这个函数里面修改name, bases, attrs的值来自由的达到我们的功能。


metaclass的使用示例

修改/增加/删除类或者实例中的方法或属性

#!/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,就可以动态添加东西了。


批量的对某些方法使用decorator,而不需要每次都在方法的上面加上@decorator_func

比如需要验证登陆或者是否有权限的,只有通过验证通过之后才可以操作,那么如果有很多个操作都需要这样做,我们一般情况下可以手动在每个方法的前头用@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的效果了。




你可能感兴趣的:(python)