6

是否可以使用 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)是可选的,只有少数函数(用于调试或前端)需要这些依赖项。这意味着在某些系统上 matplotlib 未安装在其他系统上,但在两者上都应该运行(核心)代码。因此,如果未安装 matplotlib,我想禁用某些功能。有这么优雅的方式吗?

4

3 回答 3

21

您可以使用装饰器将函数转换为无操作(记录警告):

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
于 2013-07-30T11:42:28.447 回答
2

Martijns 答案涉及将函数转换为 noops,我将解释如何实际将它们从类中删除 - 这可能是矫枉过正,我会接受 Martijns 答案的变体,它会引发某种异常。但无论如何:

您可以使用类装饰器从类中删除受影响的函数。这个需要一个布尔值和一个要删除的属性列表:

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
于 2013-07-30T11:56:17.860 回答
1

从类中删除方法对我来说似乎很奇怪。为什么不使用 try / except

plot_avail = True   
try:
    import matplotlib   
except:
    plot_avail = False

然后在你的函数中

def x(self):
    if not plot_avail: return

所以没有调用结束:类没有属性 X

于 2020-02-18T14:03:26.747 回答