如果我有以下功能:
def intercept(func): # do something here @intercept(arg1=20) def whatever(arg1,arg2): # do something here
我想拦截仅在arg1为20时启动.我希望能够将命名参数传递给函数.我怎么能做到这一点?
这是一个小代码示例:
def intercept(func): def intercepting_func(*args,**kargs): print "whatever" return func(*args,**kargs) return intercepting_func @intercept(a="g") def test(a,b): print "test with %s %s" %(a,b) test("g","d")
抛出以下异常TypeError:intercept()得到一个意外的关键字参数'a'
记住这一点
@foo def bar(): pass
相当于:
def bar(): pass bar = foo(bar)
所以,如果你这样做:
@foo(x=3) def bar(): pass
这相当于:
def bar(): pass bar = foo(x=3)(bar)
所以你的装饰师需要看起来像这样:
def foo(x=1): def wrap(f): def f_foo(*args, **kw): # do something to f return f(*args, **kw) return f_foo return wrap
换句话说,def wrap(f)
它实际上是装饰器,foo(x=3)
是一个返回装饰器的函数调用.
from functools import wraps def intercept(target,**trigger): def decorator(func): names = getattr(func,'_names',None) if names is None: code = func.func_code names = code.co_varnames[:code.co_argcount] @wraps(func) def decorated(*args,**kwargs): all_args = kwargs.copy() for n,v in zip(names,args): all_args[n] = v for k,v in trigger.iteritems(): if k in all_args and all_args[k] != v: break else: return target(all_args) return func(*args,**kwargs) decorated._names = names return decorated return decorator
例:
def interceptor1(kwargs): print 'Intercepted by #1!' def interceptor2(kwargs): print 'Intercepted by #2!' def interceptor3(kwargs): print 'Intercepted by #3!' @intercept(interceptor1,arg1=20,arg2=5) # if arg1 == 20 and arg2 == 5 @intercept(interceptor2,arg1=20) # elif arg1 == 20 @intercept(interceptor3,arg2=5) # elif arg2 == 5 def foo(arg1,arg2): return arg1+arg2 >>> foo(3,4) 7 >>> foo(20,4) Intercepted by #2! >>> foo(3,5) Intercepted by #3! >>> foo(20,5) Intercepted by #1! >>>
functools.wraps
做维基上的"简单装饰"; 更新__doc__
,__name__
以及装饰器的其他属性.