Prevent decorator from being used twice on the same function in python
我有个装修师:
1 2 3 4 5 6 7 | from functools import wraps def d(f): @wraps(f) def wrapper(*args,**kwargs): print 'Calling func' return f(*args,**kwargs) return wrapper |
我想防止它两次装饰同一个功能,例如,防止:
1 2 3 4 | @d @d def f(): print 2 |
我能想到的唯一可能的解决方案是使用dict来存储修饰器已经修饰的函数,如果要求修饰dict中存在的函数,则会引发异常。如果你有更好的主意…
我还将提出我的解决方案:
首先,创建另一个装饰器:
1 2 3 4 5 6 7 8 9 10 11 12 | 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:
1 2 3 | @DecorateOnce def decorate(f): def wrapper... |
我将信息存储在函数本身中。如果多个修饰符决定使用同一个变量,则存在冲突的风险,但是如果它只是您自己的代码,则应该能够避免冲突。
1 2 3 4 5 6 7 8 9 | 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 |
另一种选择是:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
这假定您控制所有使用的装饰器。如果有一个装饰器不复制
noam,
1 2 3 4 5 6 7 8 | 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_"部分。Lalinsky的方法,它使用一个显式定义的附加到函数对象的属性。这可能更可取,因为"包装器"名称可以在其他地方使用…
看看