此係列文檔:python
#它不是黑魔法,只是給包裝(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
關於將參數傳遞給裝飾器自己,您怎麼認爲?code
由於裝飾器必須接受一個函數做爲參數,因此這可能會有些彆扭。orm
所以,您不能將裝飾函數的參數直接傳遞給裝飾器。文檔
在尋求解決方案以前,讓咱們寫一些提醒:get
#裝飾器是普通函數 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
標記了的函數。it
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.
絕不奇怪,跟咱們前邊演示的內容同樣。
讓咱們再作一次徹底同樣的事情,可是此次咱們跳過全部討厭的中間變量:
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.
讓咱們把它變的更精簡:
@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.
嘿,你看到了嗎?咱們使用了帶有「 @
」語法的函數調用!
所以,回到帶有參數的裝飾器。
若是咱們可使用函數即時生成裝飾器,則能夠將參數傳遞給該函數,對嗎?
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小站