[英]Add positional parameters to decorator
Suppose such a quick decorator example: 假设这样一个快速的装饰器示例:
def read_a_book():
return "I am reading the book: "
def add_a_book(func):
def wrapper():
return func() + "Python Cookbook"
return wrapper
Run it and come by 运行它来
In [7]: read_a_book = add_a_book(read_a_book)
In [8]: read_a_book()
Out[8]: 'I am reading the book: Python'
I intend to make add_a_book
general and refactor it as: 我打算使
add_a_book
通用并将其重构为:
def add_a_book(func, book):
def wrapper():
return func() + book
return wrapper
Run it and get: 运行它并获得:
In [7]: read_a_book = add_a_book(read_a_book,"Python")
In [8]: read_a_book()
Out[8]: 'I am reading the book: Python'
It works as intended, 它按预期工作,
However, it throw errors when I tried symbol @ 但是,当我尝试符号@时会抛出错误
In [10]: @add_a_book("Python")
...: def read_a_book():
...: return "I am reading the book: "
TypeError: add_a_book() missing 1 required positional argument: 'book'
#additionaly
In [11]: @add_a_book
...: def read_a_book():
...: return "I am reading the book: "
TypeError: add_a_book() missing 1 required positional argument: 'book'
In [12]: @add_a_book()
...: def read_a_book("python"):
...: return "I am reading the book: "
^
SyntaxError: invalid syntax
How to solve such a problem when add parameters to decorator? 向装饰器添加参数时如何解决这样的问题?
You don't want a decorator, but a decorator factory. 您不需要装饰器,而是装饰器工厂。 In other words, you need a function that acts as a decorator, but returns another decorator.
换句话说,您需要一个充当装饰器但返回另一个装饰器的函数。 This allows you to pass an argument and return a decorator that in turn decorates the function.
这使您可以传递参数并返回装饰器,该装饰器反过来装饰函数。
def add_a_book(book='Python'):
def decorator(func):
def out_fn(*args, **kwargs):
return str(func(*args, **kwargs)) + str(book)
return out_fn
return decorator
@add_a_book('Hello World')
def read_a_book():
return "I am reading the book: "
read_a_book()
# returns:
'I am reading the book: Hello World'
It's somewhat messy, but you can parametrize decorators like this: 有点混乱,但是您可以像这样对装饰器进行参数化:
>>> def add_a_book(book):
... def add_a_book_real(func):
... def wrapper(*args, **kwargs):
... return func(*args, **kwargs) + book
... return wrapper
... return add_a_book_real
...
>>> @add_a_book("Python")
... def read_a_book():
... return "I am reading the book: "
...
>>> read_a_book()
'I am reading the book: Python'
>>>
You can use functools.wraps
, and a decorator factory: 您可以使用
functools.wraps
和装饰器工厂:
from functools import wraps
def add_a_book(book=''):
def _add_a_book(f):
@wraps(f)
def wrapper(*args):
r = f() + book
return r
return wrapper
return _add_a_book
@add_a_book(book='my book')
def read_a_book():
return "I am reading the book: "
if __name__ == '__main__':
print(read_a_book())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.