是否可以"停用"一个python装饰器的函数?这是一个例子:
cond = False
class C:
if cond:
def x(self): print "hi"
def y(self): print "ho"
是否可以使用装饰器重写此代码,如下所示?:
class C:
@cond
def x(self): print "hi"
def y(self): print "ho"
背景:在我们的库中有一些依赖项(比如matplotlib)是可选的,这些只需要几个函数(用于debug或fronted)。这意味着在某些系统上matplotlib不安装在其他系统上,但两者都应该运行(核心)代码。因此,如果未安装matplotlib,我想禁用某些功能。有这么优雅的方式吗?
答案 0 :(得分:16)
您可以使用装饰器将函数转换为no-ops(记录警告):
def conditional(cond, warning=None):
def noop_decorator(func):
return func # pass through
def neutered_function(func):
def neutered(*args, **kw):
if warning:
log.warn(warning)
return
return neutered
return noop_decorator if cond else neutered_function
这里conditional
是装饰工厂。它根据条件返回两个装饰器中的一个。
一位装饰师只是让这个功能不受影响。另一个装饰器完全替换了装饰的功能,而不是发出警告。
使用:
@conditional('matplotlib' in sys.modules, 'Please install matplotlib')
def foo(self, bar):
pass
答案 1 :(得分:2)
Martijns回答将函数调入noops的问题,我将解释你如何将它们从类中删除 - 这可能有点过分,我会解决一个Martijns答案的变种,它会引发某种异常。但无论如何:
您可以使用类装饰器从类中删除受影响的函数。这个需要一个bool和一个要删除的属性列表:
def rm_attrs_if(cond, attrs):
if not cond:
return lambda c: c #if the condition is false, don't modify the class
def rm_attrs(cls):
d = dict(cls.__dict__) #copy class dict
for attr in attrs:
del d[attr] #remove all listed attributes
return type(cls.__name__, cls.__bases__, d) #create and return new class
return rm_attrs
像这样使用:
@rm_attrs_if(something == False, ["f1", "f2"])
class X():
def f1(): pass
def f2(): pass
def f3(): pass
答案 2 :(得分:1)
从类中删除方法对我来说似乎很奇怪。为什么不使用try / except
plot_avail = True
try:
import matplotlib
except:
plot_avail = False
然后在您的函数中
def x(self):
if not plot_avail: return
所以没有通话结束:类没有属性X