1. 程式人生 > >我終於弄懂了Python的裝飾器(二)

我終於弄懂了Python的裝飾器(二)

**此係列文件:** [1. 我終於弄懂了Python的裝飾器(一)](https://www.bigyoung.cn/posts/91/) [2. 我終於弄懂了Python的裝飾器(二)](https://www.bigyoung.cn/posts/92/) [3. 我終於弄懂了Python的裝飾器(三)](https://www.bigyoung.cn/posts/93/) [4. 我終於弄懂了Python的裝飾器(四)](https://www.bigyoung.cn/posts/94/) ## 二、裝飾器的高階用法 ### 將引數傳遞給裝飾函式 ``` #它不是黑魔法,只是給包裝(wrapper)傳遞引數: def a_decorator_passing_arguments(function_to_decorate): def a_wrapper_accepting_arguments(arg1, arg2): print("I got args! Look: {0}, {1}".format(arg1, arg2)) function_to_decorate(arg1, arg2) return a_wrapper_accepting_arguments #因為當您呼叫裝飾器返回的函式時,呼叫的包裝器(wrapper),將引數傳遞給被包裝器包裝的函式 @a_decorator_passing_arguments def print_full_name(first_name, last_name): print("My name is {0} {1}".format(first_name, last_name)) print_full_name("Peter", "Venkman") # 輸出: #I got args! Look: Peter Venkman #My name is Peter Venkman ``` ### 將引數傳遞給裝飾器 關於將引數傳遞給裝飾器本身,您怎麼認為? 因為裝飾器必須接受一個函式作為引數,所以這可能會有些彆扭。 因此,**您不能將裝飾函式的引數直接傳遞給裝飾器。** 在尋求解決方案之前,讓我們寫一些提醒: ```python #裝飾器是普通函式 def my_decorator(func): print("I am an ordinary function") def wrapper(): print("I am function returned by the decorator") func() return wrapper # 因此,你可以呼叫它,而不用 "@" def lazy_function(): print("zzzzzzzz") decorated_function = my_decorator(lazy_function) #輸出: I am an ordinary function # 它輸出了 "I am an ordinary function", 因為你只是呼叫了裝飾器,而沒有呼叫函式: # 這裡沒有什麼神奇的地方,使用'@' @my_decorator def lazy_function(): print("zzzzzzzz") #outputs: I am an ordinary function ``` 結果一樣。 `my_decorator`”被呼叫了。 因此,當您使用時`@my_decorator`,您要告訴Python,通過變數來呼叫`my_decorator`標記了的函式。 ```python def decorator_maker(): print("I make decorators! I am executed only once: " "when you make me create a decorator.") def my_decorator(func): print("I am a decorator! I am executed only when you decorate a function.") def wrapped(): print("I am the wrapper around the decorated function. " "I am called when you call the decorated function. " "As the wrapper, I return the RESULT of the decorated function.") return func() print("As the decorator, I return the wrapped function.") return wrapped print("As a decorator maker, I return a decorator") return my_decorator #讓我們新建一個裝飾器 new_decorator = decorator_maker() #輸出: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator # 讓我們裝飾這個函式 def decorated_function(): print("I am the decorated function.") decorated_function = new_decorator(decorated_function) #輸出: #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function # 讓我們呼叫這個函式 decorated_function() #輸出: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function. ``` 毫不奇怪,跟我們前邊演示的內容一樣。 讓我們再做一次完全一樣的事情,但是這次我們跳過所有討厭的中間變數: ```python def decorated_function(): print("I am the decorated function.") decorated_function = decorator_maker()(decorated_function) #輸出: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. # Finally: decorated_function() #輸出: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function. ``` 讓我們把它變的更精簡: ```python @decorator_maker() def decorated_function(): print("I am the decorated function.") #輸出: #I make decorators! I am executed only once: when you make me create a decorator. #As a decorator maker, I return a decorator #I am a decorator! I am executed only when you decorate a function. #As the decorator, I return the wrapped function. #最終: decorated_function() #輸出: #I am the wrapper around the decorated function. I am called when you call the decorated function. #As the wrapper, I return the RESULT of the decorated function. #I am the decorated function. ``` 嘿,你看到了嗎?我們使用了帶有“ `@`”語法的函式呼叫! 因此,回到帶有引數的裝飾器。 如果我們可以使用函式即時生成裝飾器,則可以將引數傳遞給該函式,對嗎? ```python def decorator_maker_with_arguments(decorator_arg1, decorator_arg2): print("I make decorators! And I accept arguments: {0}, {1}".format(decorator_arg1, decorator_arg2)) def my_decorator(func): #這裡傳遞的引數是閉包的。 #如果您對封包感到不舒服,可以忽略這點。 print("I am the decorator. Somehow you passed me arguments: {0}, {1}".format(decorator_arg1, decorator_arg2)) #不要混淆裝飾器引數和函式引數! def wrapped(function_arg1, function_arg2) : print("I am the wrapper around the decorated function.\n" "I can access all the variables\n" "\t- from the decorator: {0} {1}\n" "\t- from the function call: {2} {3}\n" "Then I can pass them to the decorated function" .format(decorator_arg1, decorator_arg2, function_arg1, function_arg2)) return func(function_arg1, function_arg2) return wrapped return my_decorator @decorator_maker_with_arguments("Leonard", "Sheldon") def decorated_function_with_arguments(function_arg1, function_arg2): print("I am the decorated function and only knows about my arguments: {0}" " {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments("Rajesh", "Howard") #輸出: #I make decorators! And I accept arguments: Leonard Sheldon #I am the decorator. Somehow you passed me arguments: Leonard Sheldon #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Sheldon # - from the function call: Rajesh Howard #Then I can pass them to the decorated function #I am the decorated function and only knows about my arguments: Rajesh Howard ``` 記住它:帶引數的裝飾器,可以將變數作為引數: ``` c1 = "Penny" c2 = "Leslie" @decorator_maker_with_arguments("Leonard", c1) def decorated_function_with_arguments(function_arg1, function_arg2): print("I am the decorated function and only knows about my arguments:" " {0} {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments(c2, "Howard") #輸出: #I make decorators! And I accept arguments: Leonard Penny #I am the decorator. Somehow you passed me arguments: Leonard Penny #I am the wrapper around the decorated function. #I can access all the variables # - from the decorator: Leonard Penny # - from the function call: Leslie Howard #Then I can pass them to the decorated function #I am the decorated function and only know about my arguments: Leslie Howard ``` 如您所見,您可以像任何函式傳遞引數一樣傳遞引數給裝飾器。 您甚至可以根據需要使用`*args, **kwargs`。 但是請記住,裝飾器**僅**被呼叫**一次**,僅在Python匯入指令碼時。之後,您將無法動態設定引數。 當您執行“ import x”時,**該函式已經被修飾**,因此您無法進行任何更改。 > 本文首發於[BigYoung小站](http://bigy