簡體   English   中英

將位置參數添加到裝飾器

[英]Add positional parameters to decorator

假設這樣一個快速的裝飾器示例:

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

向裝飾器添加參數時如何解決這樣的問題?

您不需要裝飾器,而是裝飾器工廠。 換句話說,您需要一個充當裝飾器但返回另一個裝飾器的函數。 這使您可以傳遞參數並返回裝飾器,該裝飾器反過來裝飾函數。

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'

有點混亂,但是您可以像這樣對裝飾器進行參數化:

>>> 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'
>>>

您可以使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM