我有一个装饰者:
from functools import wraps
def d(f):
@wraps(f)
def wrapper(*args,**kwargs):
print 'Calling func'
return f(*args,**kwargs)
return wrapper
我想阻止它两次装饰相同的功能,例如防止:
@d
@d
def f():
print 2
我能想到的唯一可能的解决方案是使用dict来存储装饰器已经装饰的函数,并在被要求装饰dict中存在的函数时引发异常。 告诉你是否有更好的想法...
答案 0 :(得分:2)
我将信息存储在函数本身中。如果多个装饰者决定使用相同的变量,则存在冲突的风险,但如果它只是您自己的代码,那么您应该能够避免它。
def d(f):
if getattr(f, '_decorated_with_d', False):
raise SomeException('Already decorated')
@wraps(f)
def wrapper(*args,**kwargs):
print 'Calling func'
return f(*args,**kwargs)
wrapper._decorated_with_d = True
return wrapper
另一个选择是:
def d(f):
decorated_with = getattr(f, '_decorated_with', set())
if d in decorated_with:
raise SomeException('Already decorated')
@wraps(f)
def wrapper(*args,**kwargs):
print 'Calling func'
return f(*args,**kwargs)
decorated_with.add(d)
wrapper._decorated_with = decorated_with
return wrapper
这假定您控制所有使用的装饰器。如果有一个装扮器没有复制_decorated_with
属性,你就不会知道装饰的是什么。
答案 1 :(得分:2)
我也会提出我的解决方案:
首先,创建另一个装饰器:
class DecorateOnce(object):
def __init__(self,f):
self.__f=f
self.__called={} #save all functions that have been decorated
def __call__(self,toDecorate):
#get the distinct func name
funcName=toDecorate.__module__+toDecorate.func_name
if funcName in self.__called:
raise Exception('function already decorated by this decorator')
self.__called[funcName]=1
print funcName
return self.__f(toDecorate)
现在你用这个装饰器装饰的每个装饰器都会限制自己只装饰一次func:
@DecorateOnce
def decorate(f):
def wrapper...
答案 2 :(得分:0)
Noam,func_code
使用的属性为co_name
。如下所示,所有改变的是d()的def
def d(f):
if f.func_code.co_name == 'wrapper':
return f #ignore it (or can throw exception instead...)
@wraps(f)
def wrapper(*args, **kwargs):
print 'calling func'
return f(*args, **kwargs)
return wrapper
另外,请参阅LukášLalinský的方法,该方法使用附加到函数对象的显式定义的属性。这可能是优选的,因为“包装”名称可能在其他地方使用...
答案 3 :(得分:-1)
查看f.func_code
,它可以告诉您f是函数还是包装器。