python 装饰器
2014-04-27 12:51
183 查看
一、 装饰器
装饰器是在python 2.4 中新加入的,使得函数和方法封装更容易阅读和理解。对一个函数进行封装,使得函数在调用时,完成一些额外的工作,类似于AOP。
在引入装饰器之前,语法如下:
class WhatFor(object): def it(cls): print 'work with %s' % cls #定义it为类方法 it = classmethod(it) def uncommon(): print 'I could be a global function' #定义uncommon为静态方法 uncommon = staticmethod(uncommon)
有了装饰器后
class WhatFor1(object): @classmethod def it(cls): print 'work with %s' % cls @staticmethod def uncommon(): print 'I could be a global function'
二、编写装饰器
编写装饰器最简单、最容易理解的方法:编写一个函数,返回封装了原始函数(被装饰的函数)一个子函数。def mydecorator(fun): #子函数,封装原始函数 def _mydecorator(*args, **kw): print 'before work' res = fun(*args, **kw) print 'after work' return res #返回子函数 return _mydecorator @mydecorator def func(): print 'function work' func()
常见的装饰模式 或者说是功能有:
参数检查缓存
代理
上下文提供者
三、 参数检查
在有些环境中,需要检查函数接收或者返回的参数,装饰器可以提供函数自省能力。from itertools import izip rpc_info = {} def xmlrpc(in_ =(), out=(type(None),)): def _xmlrpc(function): def _xmlrpc(function): #注册签名 func_name = function.func_name rpc_info[func_name] = (in_,out) def _check_types(elements, types): """Subfunction that checks the types.""" if len(elements) != len(types): raise TypeError('参数数量不对') typed = enumerate(izip(elements, types)) for index, couple in typed: arg, of_the_right_type = couple if isinstance(arg, of_the_right_type): continue raise TypeError('arg #%d should be %s' %(index, of_the_right_type)) #类型不对,抛出typeerror #封装函数 def _xmlrpc(*args): #检查输入的内容 checkable_args = args[1:] _check_types(checkable_args, in_) #执行函数 res = function(*args) #检查输出的内容 if not type(res) in (tuple, list): checkable_res=(res,) else: checkable_res=res _check_types(checkable_res, out) return res return _xmlrpc return _xmlrpc #使用实例 class RPCView(object): # 2个 int 输入, 没有返回 @xmlrpc((int, int)) def meth1(self, int1, int2): print 'recieve %d and %d' % (int1, int2) # 一个str输入,一个int输出 @xmlrpc((str,), (int,)) def meth2(self ,phrase): print 'recieve %s' % phrase return 12 print rpc_info my = RPCView() #传入参数合乎要求 my.meth1(1,2) #传入参数类型不对,抛出类型错误 my.meth2(2)
四、缓存
在要求高效的环境中,通常的优化手段是使用缓存。缓存装饰器把函数的传入参数和结果配对记录下来,下来调用函数时,先从记录中查找,直接返回。适用于输入参数值有限的环境。import time import hashlib import pickle from itertools import chain cache = {} def is_obsolete(entry,duration): return time.time() - entry['time'] > duration def compute_key(function, args, kw): key = pickle.dumps((function.func_name,args,kw)) return hashlib.sha1(key).hexdigest() def memoize(duration=10): def _memoize(function): def _memoize(*args, **kw): key = compute_key(function, args, kw) #检查缓存中是否已经有了,而且没有过期 if (key in cache and not is_obsolete(cache[key],duration)): print 'we got a winner' return cache[key]['value'] #如果没有或者已过期,则计算并放入cache中 result = function(*args,**kw) cache[key] = {'value':result,'time':time.time()} return result return _memoize return _memoize @memoize() def very_very_very_complex_stuff(a,b): return a+b very_very_very_complex_stuff(2,2) #返回的是缓存的结果 very_very_very_complex_stuff(2,2)
五、代理
代理装饰器使用一个全局机制来标识和注册函数。例如:一个有权限保护的执行函数可以使用一个集中检测器和相关可调用对象权限来实现。# -*- coding: UTF-8 –*- #用户类,包含权限 class User(object): def __init__(self, roles): self.roles = roles #自定义异常 class Unauthorized(Exception): pass def protect(role): def _protect(function): def __protect(*args, **kw): user = globals().get('user') if user is None or role not in user.roles: raise Unauthorized("I won't tell you") return function(*args, **kw) return __protect return _protect #角色1,拥有admin 和user两种权限 tarek = User(('admin','user')) #角色2,只有user权限 bill = User(('user')) class MySecrets(object): #只有admin权限才能执行此函数 @protect('admin') def waffle_recipe(self): print 'use tons of butter' these_are = MySecrets() user = tarek #有权限,可以执行 these_are.waffle_recipe() user = bill #没有权限,抛出异常 these_are.waffle_recipe()
六、上下文提供者
这种装饰器用来确保函数可以运行在正确的上下文中,或者在函数前后执行一些代码。用来设置或复位特定的执行环境。例如:当一个数据项必须与其他线程共享时,就需要一个锁来保护它。这个锁可以在一个装饰器中编写。
from threading import RLock lock = RLock() def synchronized(function): def _synchronized(*args, **kw): lock.acquire() try: return function(*args, **kw) finally: lock.release() return _synchronized @synchronized def thread_safe(): pass thread_safe()
上下文装饰器在2.5 以后可以使用with语句来代替。
相关文章推荐
- Python 装饰器浅析
- python中装饰器你真的理解吗?
- 12步教你理解Python装饰器
- Python装饰器与面向切面编程
- 面向对象使用装饰器进行修饰(python)
- python(四)下:python装饰器详解
- 理解Python装饰器(一)
- python 装饰器
- python中的装饰器
- python装饰器
- Python中使用装饰器和元编程实现结构体类实例
- Python装饰器
- python闭包与装饰器
- @修饰符--python中的装饰器
- Python 装饰器decorater
- python--装饰器
- Python装饰器学习(九步入门)
- python装饰器的使用
- 理解 Python 中的装饰器
- python里为什么需要使用装饰器(decorator)