有没有办法在python中将两个装饰器组合成一个新的装饰器?
我意识到我可以将多个装饰器应用于一个函数,但我很好奇是否有一些简单的方法将两个组合成一个新的.
Joc*_*zel 51
更一般:
def composed(*decs):
def deco(f):
for dec in reversed(decs):
f = dec(f)
return f
return deco
Run Code Online (Sandbox Code Playgroud)
然后
@composed(dec1, dec2)
def some(f):
pass
Run Code Online (Sandbox Code Playgroud)
相当于
@dec1
@dec2
def some(f):
pass
Run Code Online (Sandbox Code Playgroud)
Tha*_*tos 23
是.在这里查看装饰器的定义.
这样的事情应该有效:
def multiple_decorators(func):
return decorator1(decorator2(func))
@multiple_decorators
def foo(): pass
Run Code Online (Sandbox Code Playgroud)
小智 6
如果您不想在测试套件中重复太多,您可以这样做:
def apply_patches(func):
@functools.wraps(func)
@mock.patch('foo.settings.USE_FAKE_CONNECTION', False)
@mock.patch('foo.settings.DATABASE_URI', 'li://foo')
@mock.patch('foo.connection.api.Session.post', autospec=True)
def _(*args, **kwargs):
return func(*args, **kwargs)
return _
Run Code Online (Sandbox Code Playgroud)
现在您可以在测试套件中使用它,而不是在每个函数上方使用大量的装饰器::
def ChuckNorrisCase(unittest.TestCase):
@apply_patches
def test_chuck_pwns_none(self):
self.assertTrue(None)
Run Code Online (Sandbox Code Playgroud)
如果装饰器不接受额外的参数,你可以使用
def compose(f, g):
return lambda x: f(g(x))
combined_decorator = compose(decorator1, decorator2)
Run Code Online (Sandbox Code Playgroud)
现在
@combined_decorator
def f():
pass
Run Code Online (Sandbox Code Playgroud)
将等价于
@decorator1
@decorator2
def f():
pass
Run Code Online (Sandbox Code Playgroud)
装饰器只是将一个函数作为输入并返回一个新函数的函数。这个:
@deco
def foo():
...
Run Code Online (Sandbox Code Playgroud)
等效于此:
def foo():
...
foo = deco(foo)
Run Code Online (Sandbox Code Playgroud)
换句话说,装饰函数(foo)作为参数传递给装饰器,然后foo被装饰器的返回值替换。有了这些知识,编写结合了两个其他装饰器的装饰器很容易:
def merged_decorator(func):
return decorator2(decorator1(func))
# now both of these function definitions are equivalent:
@decorator2
@decorator1
def foo():
...
@merged_decorator
def foo():
...
Run Code Online (Sandbox Code Playgroud)
如果装饰器接受参数,则变得有些棘手,例如以下两个:
@deco_with_args2(bar='bar')
@deco_with_args1('baz')
def foo():
...
Run Code Online (Sandbox Code Playgroud)
您可能想知道这些装饰器是如何实现的。它实际上非常简单:deco_with_args1并且deco_with_args2是返回另一个函数装饰器的函数。具有参数的装饰器实质上是装饰器工厂。等效于:
@deco_with_args('baz')
def foo():
...
Run Code Online (Sandbox Code Playgroud)
这是:
def foo():
...
real_decorator = deco_with_args('baz')
foo = real_decorator(foo)
Run Code Online (Sandbox Code Playgroud)
为了使装饰器接受参数,然后应用其他两个装饰器,我们必须实现自己的装饰器工厂:
def merged_decorator_with_args(bar, baz):
# pass the arguments to the decorator factories and
# obtain the actual decorators
deco2 = deco_with_args2(bar=bar)
deco1 = deco_with_args1(baz)
# create a function decorator that applies the two
# decorators we just created
def real_decorator(func):
return deco2(deco1(func))
return real_decorator
Run Code Online (Sandbox Code Playgroud)
然后可以像下面这样使用此装饰器:
@merged_decorator_with_args('bar', 'baz')
def foo():
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10782 次 |
| 最近记录: |