1. 程式人生 > >python3 如何給裝飾器傳遞參數

python3 如何給裝飾器傳遞參數

還要 經典 missing .py 簡潔 nbsp required 裝飾 最簡

引子

  之前寫過一篇文章用來講解裝飾器(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+y


def 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 如何給裝飾器傳遞參數