在两个python修饰符之间传递变量

2024-09-29 22:18:30 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有办法在应用于同一函数的两个python装饰器之间传递变量?目标是让一个装饰师知道另一个也被应用了。我需要以下示例中的decobar_present()之类的东西:

def decobar(f):
    def wrap():
        return f() + "bar"
    return wrap

def decofu(f):
    def wrap():
        print decobar_present() # Tells me whether decobar was also applied
        return f() + "fu"
    return wrap

@decofu
@decobar
def important_task():
    return "abc"

一般来说,我希望能够根据decobar是否也被应用来修改decofu的行为。在


Tags: 函数示例目标returndefbar装饰print
3条回答

每个装饰器都可以包装另一个函数。传递给decofu()的函数是decobar()修饰符的结果。在

只要测试decobar包装的特定特征,只要使包装可识别:

def decobar(f):
    def wrap():
        return f() + "bar"
    wrap.decobar = True
    return wrap

def decofu(f):
    def wrap():
        print 'decobar!' if getattr(f, 'decobar') else 'not decobar'
        return f() + "fu"
    return wrap

我在wrapper函数上使用了一个任意属性,但是您可以尝试测试名称(不是那么明确)、签名(可能使用inspect.getargspec())等

这仅限于直接包装。在

一般来说,你不想把装修工像这样紧密地结合在一起。找出一个不同的解决方案,并且只依赖于函数签名或返回值。在

decobar应用于“registry”时,可以将其添加到“registry”,然后检查注册表以确定decobar是否应用于该函数。这种方法需要保持原始函数的__module__和{}属性的完整性(在包装函数上使用functools.wraps)。在

import functools

class decobar(object):
    registry = set()

    @classmethod
    def _func_key(cls, f):
        return '.'.join((f.__module__, f.func_name))

    @classmethod
    def present(cls, f):
        return cls._func_key(f) in cls.registry

    def __call__(self, f):
        self.registry.add(self._func_key(f))

        @functools.wraps(f)
        def wrap():
            return f() + "bar"
        return wrap

# Make the decorator singleton
decobar = decobar()

def decofu(f):
    @functools.wraps(f)
    def wrap():
        print decobar.present(f) # Tells me whether decobar was also applied
        return f() + "fu"
    return wrap

@decofu
@decobar
def important_task():
    return "abc"

使用一个类来实现decobar,因为它将registry和{}保存在一个名称空间中(IMO,这感觉更干净了)

虽然操作stack trace是可能的,但我认为,最好是创建一个函数decofubar,并尽可能多地合并“fu”和“bar”。至少,它会使你的代码更清晰、更明显。在

相关问题 更多 >

    热门问题