【碎片】利用 with 语法实现可拆卸的装饰器

来源:转载

Python 自 2.5 版本以来就支持 with 语法,用来实现带有“进入”和“退出”动作的上下文的管理,文件操作、数据库事务等都可以通过其实现。with statement 的协议也是开放的,带有 __enter__ 和 __exit__ 方法的类都可以作为有效的上下文环境。

在 AOP 方面,我们也可以利用 with 语法实现一种可拆卸的装饰器——在 with 的环境下,目标对象被安装装饰器,一旦退出 with 环境,装饰器也自动拆除。

下面的碎片代码就是一个例子,其功能是跟踪一个类中所有方法调用的轨迹(这个例子都被用烂了,和 Java 的银行转帐例子有的一拼了)。

 1 #!/usr/bin/env python

2 # coding:utf-8

3

4 import functools

5 import types 6 import hashlib
7 import time
8
9 class MethodTrace(object):
10 """
11 类方法调用轨迹
12 """
13 def __init__(self, cls):
14 self.target = cls
15 self.origin = {}
16
17 def __enter__(self):
18 # 轨迹装饰器
19 def tracing(func):
20 @functools.wraps(func)
21 def tracing_wrapper(*args, **kwargs):
22 result = func(*args, **kwargs)
23 print("== %s : %s has been called ==" % (time.ctime(), func))
24 return result
25 return tracing_wrapper
26 # 遍历目标类, 安装装饰器
27 for attr_name in self.target.__dict__:
28 attr = getattr(self.target, attr_name)
29 if type(attr) is types.MethodType:
30 # 保留原始函数
31 self.origin[attr_name] = attr
32 # 装饰
33 self._set_target(attr_name, tracing(attr))
34 return self.target
35
36 def __exit__(self, except_type, except_value, except_trac):
37 # 卸载轨迹装饰器
38 for k,v in self.origin.items():
39 self._set_target(k,v)
40
41 def _set_target(self, name, value):
42 setattr(self.target, name, value)
43
44 class Demo(object):
45 def __init__(self, name):
46 self.name = name
47
48 def hash_name(self):
49 md5 = hashlib.md5()
50 md5.update(self.name)
51 self.name = md5.hexdigest()
52
53 def demo():
54 demo = Demo('tonyseek')
55 demo.hash_name()
56 print(demo.name)
57
58 def tips(content):
59 print("/n### %s ###/n" % content)
60
61 if __name__ == '__main__':
62 tips("Without Decoration")
63 demo()
64 tips("With Decoration")
65 with MethodTrace(Demo):
66 demo()
67 tips("Uninstalled Decorater")
68 demo()

可以看出,在 with 上下文的内部,Demo 类被装饰。一旦退出,则完全还原。运行效果如下:


分享给朋友:
您可能感兴趣的文章:
随机阅读: