使用Python的元类实现AOP监控类方法调用过程
来源:互联网 发布:千里眼淘宝插件手机版 编辑:程序博客网 时间:2024/04/30 11:39
引言
Python的元类(metaclass)功能强大,能够实现AOP(Aspect-Oriented Programming,面向切面编程)的类似功能,本文以实现监控类方法执行所耗时间为例,参照本文,可以实现记录类方法调用参数和执行结果到日志文件中,统一增加类的方法或属性等看似“不可能”的事情而不用对其它类做修改,达到“高内聚,低耦合”的目的。
什么是元类(metaclass)
简而言之,元类就是类的类(The class of a class)。有点拗口和抽象啊,呵呵,不过该定义非常恰当啊。定义类会创建一个类名称,一个类的字典,一个基类列表。元类就是负责利用这三个参数和创建类。大部分面向对象编程(OOP)的语言提供一个缺省实现,而Python的特殊之处在于,我们可以创建定制的元类。大部分Python程序员都不会用到元类这一工具,但是当我们的需求出现时,元类能够提供一个强大和优雅的解决方案。它已经使用在记录属性访问,增加线程安全,跟踪对象创建,实现单例(Singleton)和许多其他任务。
定制类的创建原理
缺省情况下,新型的类构造使用 type(), 一个类的定义被读入一个不同的名字空间,类名称的值绑定到 type(name,bases,dict)的结果上。当类的定义被读入时,如果 __metaclass__定义了,赋值给它的可调用对象将取代type()而被调用,这将允许所写的类或函数能够监控或者修改类的创建过程:
1.在类被创建之前修改类的字典。
2.返回另外一个类的实例--本质上扮演了工厂函数的角色。
这些步骤必须在元类的__new__()方法中完成, 然后 type.__new__() 将会通过该方法被调用,从而创建一个具有不同特性的类。
决定使用哪个合适的元类,依据以下优先规则:
1. 如果 dict['__metaclass__'] 存在,就使用它作为元类。
2.否则,如果存在有至少一个基类,那么将会使用基类的元类。
3.否则,如果存在一个全局变量 __metaclass__,那么将使用这个全局变量作为元类。
4.否则,将会使用旧形式的传统的元类(types.ClassType)。
元类使用举例--修改类的属性
下面的示例,使用元类增加一个叫“foo”的类属性,我们先看代码和运行结果:
#!/usr/bin/env python#-*- coding: utf-8 -*-#@author : Thomas Hu#@date : 2015-04-13#@version : 1.0class MyMetaClass(type): def __new__(mcs, name, bases, dict): dict['foo'] = 'foo in MyMetaClass' return type.__new__(mcs, name, bases, dict) class MyClass(object): __metaclass__ = MyMetaClassif __name__ == "__main__": myobj = MyClass() print myobj.foo print myboj.bar输出结果:
>>> foo in MyMetaClassTraceback (most recent call last): File "D:\temp\metaclass\simple.py", line 18, in <module> print myboj.barNameError: name 'myboj' is not defined>>>由于在元类“MyMetaClass”中,我们在类字典中增加了 “foo”属性,所以调用 myobj.foo 不会出错,而且打印出值;但对于 myobj.bar,由于 “bar”属性并没有在元类"MyMetaClass"中添加,也没有在 "MyClass"类中定义,所以出错。
注:元类会覆盖原类定义的属性。例如,如果在 MyClass中增加一个属性,设置为 foo="foo in MyClass",输出的 myobj.foo的值仍然为“foo in MyMetaClass"。
元类使用举例--监控类方法调用
#!/usr/bin/env python#-*- coding: utf-8 -*-#@author : Thomas Hu#@date : 2015-04-13#@version : 1.0import typesimport timeimport functoolsdef timefunc(func): '''Calculate the execution time of func.''' @functools.wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print("Function \"%s\" execute cost %d seconds."%(func.__name__, end - start)) return result return wrapperclass MonitorMetaClass(type): def __new__(mcs, name, bases, attr_dict): for k, v in attr_dict.items(): # If the attribute is function type, use the wrapper function instead if isinstance(v, types.FunctionType): attr_dict[k] = timefunc(v) return type.__new__(mcs, name, bases, attr_dict) class TestClass(object): __metaclass__ = MonitorMetaClass def count_range(self, n): count = 0 for i in range(n): count += i self._sleep() return count def _sleep(self, n=1): time.sleep(n)if __name__ == "__main__": obj = TestClass() value = obj.count_range(5) print("value=%d"%(value))执行结果如下:
>>> Function "_sleep" execute cost 1 seconds.Function "_sleep" execute cost 1 seconds.Function "_sleep" execute cost 1 seconds.Function "_sleep" execute cost 1 seconds.Function "_sleep" execute cost 1 seconds.Function "count_range" execute cost 5 seconds.value=10>>>
元类使用举例--实现singleton模式
#!/usr/bin/env python#-*- coding: utf-8 -*-#@author : Thomas Hu#@date : 2015-04-13#@version : 1.0class SingletonMetaClass(type): def __init__(mcs, name, bases, attr_dict): type.__init__(mcs, name, bases, attr_dict) mcs._instance = None def __call__(mcs, *args, **kwargs): if mcs._instance is None: mcs._instance = type.__call__(mcs, *args, **kwargs) return mcs._instance class TestClass(object): __metaclass__ = SingletonMetaClass name = "test class"if __name__ == "__main__": obj1 = TestClass() obj2 = TestClass() print("obj1 id=%s, name=%s"%(id(obj1), obj1.name)) print("obj2 id=%s, name=%s"%(id(obj2), obj2.name)) obj1.name = "name changed" print("obj1 id=%s, name=%s"%(id(obj1), obj1.name)) print("obj2 id=%s, name=%s"%(id(obj2), obj2.name))输出结果如下:
>>> obj1 id=46617392, name=test classobj2 id=46617392, name=test classobj1 id=46617392, name=name changedobj2 id=46617392, name=name changed>>>由此可见,以上代码确实实现了单例模式,obj1和obj2的id值都相同,修改其中任意一个对象的属性,另外一个对象的属性也跟着变化(id都相同了,就是同一个对象了)。
小结
- 使用Python的元类实现AOP监控类方法调用过程
- python总结(六):元类与方法的默认实现
- 使用ASM4.0实现AOP的功能,监控每个方法的执行时间
- Python使用元类
- python 使用元类
- Spring Bean中方法调用/http请求调用/存储过程调用实现的工具类
- spring aop 实现方法执行时间监控
- spring aop 实现方法执行时间监控
- Python实现子类调用父类的方法
- python子类调用父类的构造方法实现方案
- 使用Spring AOP前置通知实现提高方法调用的安全性能
- Case:接口实现类的方法上使用AspectJ方式实现aop的异常问题
- python 类方法 的调用
- AOP代理类中调用带有annotation的私有方法
- 使用注解实现AOP的方法
- spring aop 同一个类中一个方法调用另一个方法,拦截不到被调用的方法
- python的元类
- spring aop实现的过程
- lavaral5:实验楼构建大型网站(未完)
- DBCP连接池配置参数说明
- VC++ 声音处理
- 关于IOS开发是用xib/storyboard还是纯代码开发
- unix环境高级编程——库函数的缓冲区
- 使用Python的元类实现AOP监控类方法调用过程
- RFID作业(第三次)
- java的xml学习[JDOM方式解析XML文档]
- leetCode | Add Two Numbers
- STM32Fxx系列CAN总线配置总结
- Java获取本机ip的方法
- LeetCode(034) Search For a Range (Java)
- Linux下使用Shell脚本实现ftp的自动上传下
- 即时通信之Bmob开发11