在两个python装饰器之间传递变量
是否有一种方法可以在应用于同一函数的两个python装饰器之间传递变量?目标是让其中一个装饰师知道另一个也被应用了。我需要以下示例中的类似decobar_present()的内容:在两个python装饰器之间传递变量,python,decorator,chaining,Python,Decorator,Chaining,是否有一种方法可以在应用于同一函数的两个python装饰器之间传递变量?目标是让其中一个装饰师知道另一个也被应用了。我需要以下示例中的类似decobar_present()的内容: def decobar(f): def wrap(): return f() + "bar" return wrap def decofu(f): def wrap(): print decobar_present() # Tells me whether d
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的行为 虽然可以操作,但我认为,您最好创建一个函数
decofubar
,并尽可能多地合并“fu”和“bar”。至少,它会使您的代码更干净、更明显。虽然可以操作,但我认为,您最好创建一个函数decofubar
,并尽可能多地合并“fu”和“bar”。至少,它会使您的代码更干净、更明显。每个装饰程序都可以包装另一个函数。传递给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
我在包装器函数上使用了一个任意属性,但是您可以尝试测试名称(不是很明确)、签名(可能使用inspect.getargspec()
等)
这仅限于直接包装
一般来说,你不想把装饰师紧密地结合在一起。制定一个不同的解决方案,只依赖于函数签名或返回值。每个装饰器都可以包装另一个函数。传递给
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
我在包装器函数上使用了一个任意属性,但是您可以尝试测试名称(不是很明确)、签名(可能使用inspect.getargspec()
等)
这仅限于直接包装
一般来说,你不想把装饰师紧密地结合在一起。制定一个不同的解决方案,只依赖于函数签名或返回值。您可以在
decobar
中为f
(或者更确切地说是wrap
)指定标志,如下所示
def decobar(f):
def wrap():
return f() + "bar"
wrap.decobar_applied = True
return wrap
def decofu(f):
def wrap():
if hasattr(f, 'decobar_applied') and f.decobar_applied:
print decobar_present() # Tells me whether decobar was also applied
return f() + "fu"
return wrap
@decofu
@decobar
def important_task():
return "abc"
您可以像这样在
decobar
中为f
(或者更确切地说是wrap
)分配标志
def decobar(f):
def wrap():
return f() + "bar"
wrap.decobar_applied = True
return wrap
def decofu(f):
def wrap():
if hasattr(f, 'decobar_applied') and f.decobar_applied:
print decobar_present() # Tells me whether decobar was also applied
return f() + "fu"
return wrap
@decofu
@decobar
def important_task():
return "abc"
当
decobar
应用于函数时,您可以将函数添加到“注册表”,然后检查注册表以确定是否将decobar
应用于函数。这种方法要求保留原始函数的\uuuu模块\uuuu
和\uuuu名称\uuuu
属性不变(使用functools.wrapps
覆盖包装函数)
使用一个类来实现
decobar
,因为它将registry
和present()
保存在一个名称空间中(在我看来,这个名称空间比较干净)当应用decobar
时,可以将函数添加到“注册表”中,然后稍后检查注册表以确定是否将decobar
应用于该函数。这种方法要求保留原始函数的\uuuu模块\uuuu
和\uuuu名称\uuuu
属性不变(使用functools.wrapps
覆盖包装函数)
使用一个类来实现
decobar
,因为它将registry
和present()
保存在一个名称空间中(IMO感觉很干净)要在两个python装饰器之间传递变量,可以使用修饰函数的关键字参数字典。只是不要忘记在从第二个decorator中调用函数之前,从那里弹出添加的参数
def decorator1(func):
def wrap(*args, **kwargs):
kwargs['cat_says'] = 'meow'
return func(*args, **kwargs)
return wrap
def decorator2(func):
def wrap(*args, **kwargs):
print(kwargs.pop('cat_says'))
return func(*args, **kwargs)
return wrap
class C:
@decorator1
@decorator2
def spam(self, a, b, c, d=0):
print("Hello, cat! What's your favourite number?")
return a + b + c + d
x=C()
print(x.spam(1, 2, 3, d=7))
要在两个python装饰器之间传递变量,可以使用装饰函数的关键字参数字典。只是不要忘记在从第二个decorator中调用函数之前,从那里弹出添加的参数
def decorator1(func):
def wrap(*args, **kwargs):
kwargs['cat_says'] = 'meow'
return func(*args, **kwargs)
return wrap
def decorator2(func):
def wrap(*args, **kwargs):
print(kwargs.pop('cat_says'))
return func(*args, **kwargs)
return wrap
class C:
@decorator1
@decorator2
def spam(self, a, b, c, d=0):
print("Hello, cat! What's your favourite number?")
return a + b + c + d
x=C()
print(x.spam(1, 2, 3, d=7))
你为什么需要这个?这些装饰师在干什么?你为什么需要这个?这些修饰符在做什么?注意:只有在
decofu
和decobar
@user2357112:确实没有其他修饰符的情况下,这才有效。注意:只有在decofu
和decobar
@user2357112:确实没有其他修饰符的情况下,这才有效。我想我将为所有人实现一个中央注册表装饰师。谢谢你以上的想法!我想我将为所有装饰者实现一个中央注册中心。谢谢你以上的想法!