python3 如何給裝飾器傳遞參數
【引子】
之前寫過一篇文章用來講解裝飾器(https://www.cnblogs.com/JiangLe/p/9309330.html) 、那篇文章的定位是入門級的
所以也就沒有講過多的高級主題,決定在這裏講一下如果為裝飾器傳遞參數
【目標】
我們有兩個函數“add_fun”、“add” 其中“add_fun”已經過時、如果用戶有調用這個函數的話就提示它“add_fun”已經過時並且引導
它去調用“add”函數
【add\add_fun函數的定義】
def add_fun(x,y): """ 實現兩個數相加、並返回合 """ return x+ydef add(x,y): """ 實現兩個數相加、並返回合 """ return x+y
【通過裝飾器引導調用add_fun的用戶去調用add】
def deprecated(fun,new_fun_name): """deprecated函數會返回一個叫inner的函數、inner函數會返回 fun調用的結果,與直接調用fun得到值不同的是inner會先打印一行提示 表明fun已經過時 """ def inner(x,y): print("{fun.__name__} 函數已經過時 請使用{new_fun_name}".format(fun=fun,new_fun_name=new_fun_name)) return fun(x,y) return inner def add_fun(x,y): """ 實現兩個數相加、並返回合 """ return x+y add_fun = deprecated(add_fun,‘add‘) def add(x,y): """ 實現兩個數相加、並返回合 """ return x+y if __name__=="__main__": print(add_fun(1,1))
調用時的輸出如下:
python3 dc.py add_fun 函數已經過時 請使用add 2
【難道為裝飾器增加參數就這麽的簡單】
仔細的你可能已經發現了、我們在上面的代碼裏並沒有用裝飾器的語法糖衣、而是通過函數調用的方式來包裝的add_fun方法
add_fun = deprecated(add_fun,‘add‘)
機智的你應該想到了@deprecated(‘add‘) 這樣去裝飾add_fun應該也能成吧!於是代碼如下(關鍵代碼)
@deprecated(‘add‘) def add_fun(x,y): """ 實現兩個數相加、並返回合 """ return x+y
當你調用時會發現完全不是你想要的那樣、
python3 dc.py Traceback (most recent call last): File "dc.py", line 12, in <module> @deprecated(‘add‘) TypeError: deprecated() missing 1 required positional argument: ‘new_fun_name‘
事實上目前語法糖衣只解決了最簡單的情況、如果你要給@寫法 指定參數還要另尋它法。
【真理簡潔而有力】
linux的世界裏有句話“一切皆文件”,python的世界裏也有一句話“一切皆對象”; 但是關鍵不是會“背”,而是“領悟”。
一個經典的糖衣格式是這樣的
@decorate def fun(): pass
請仔細看一下不難發現@後面直接是對象名、由python的數據模式可知、對象名只是一個對象的標識;也就是說@後面是一個對象!對象可以
是已經定義好的,也可以是調用才生成。明白這一層道理之後事情就比較好辦了,我們只要在調用時生成“裝飾”對象就可以了,因為要調用
所以就給了我們傳遞參數的機會。
【觸摸真理一】
用調用時生成的對象用作裝飾器
def deprecated(new_fun_name): """derepcated 裝飾器把函數標記為過時 """ def warpper(fun): """ """ def inner(*args): print("{0} 函數已經過時 請使用 {1}".format(fun.__name__,new_fun_name)) return fun(*args) return inner return warpper decorator = deprecated(‘add‘) # 特意把這一步單獨分離出來、用於說明什麽叫調用時創建的對象用作做裝飾器 @decorator # 特意把這一步單獨分離出來、用於說明什麽叫調用時創建的對象用作做裝飾器 def add_fun(x,y): """ 實現兩個數相加、並返回合 """ return x+y def add(x,y): """ 實現兩個數相加、並返回合 """ return x+y if __name__=="__main__": print(add_fun(1,1))
【觸摸真理二】
與語法糖衣結合、完成傳遞參數的目的
def deprecated(new_fun_name): """derepcated 裝飾器把函數標記為過時 """ def warpper(fun): """ """ def inner(*args): print("{0} 函數已經過時 請使用 {1}".format(fun.__name__,new_fun_name)) return fun(*args) return inner return warpper @deprecated(‘add‘) def add_fun(x,y): """ 實現兩個數相加、並返回合 """ return x+y def add(x,y): """ 實現兩個數相加、並返回合 """ return x+y if __name__=="__main__": print(add_fun(1,1))
調用時輸出如下
python3 dc.py add_fun 函數已經過時 請使用 add 2
總結:
如果只能用一名話概括python我想對簡潔的應該是“一切皆對象”了吧。
python3 如何給裝飾器傳遞參數