您的位置:首页 > 编程语言 > Python开发

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

2015-09-12 10:55 781 查看

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的效果了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: