假设有这样一个快速装饰器的例子:
def read_a_book():
return "I am reading the book: "
def add_a_book(func):
def wrapper():
return func() + "Python Cookbook"
return wrapper
运行它并通过
来In [7]: read_a_book = add_a_book(read_a_book)
In [8]: read_a_book()
Out[8]: 'I am reading the book: Python'
我打算让add_a_book
一般化并将其重构为:
def add_a_book(func, book):
def wrapper():
return func() + book
return wrapper
运行并获取:
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'
按预期工作,
但是,当我尝试使用符号@
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
如何在向装饰器添加参数时解决这个问题?
答案 0 :(得分:3)
你不需要装饰师,而是装饰工厂。换句话说,您需要一个充当装饰器的函数,但返回另一个装饰器。这允许您传递一个参数并返回一个装饰器,该装饰器依次修饰该函数。
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'
答案 1 :(得分:1)
它有些混乱,但你可以像这样参数化装饰器:
>>> 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'
>>>
答案 2 :(得分:1)
您可以使用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())