Python 裝飾器

裝飾器引入

有函數(shù)如下:(用來讀取文件內(nèi)容并顯示)

def readFile(file):
    f = open(file, 'r', encoding="utf-8")
    for line in f.readlines():
        print(line)
    f.close()

是(sei)讀取文件哪有這樣寫的,打開前不檢查文件是否存在,而且讀文件操作也可能會出錯。一般情況下我們會推薦with open(path, 'r', encoding='utf-8') as f: 但是今天我們我們故意不用改方法,我們可以封裝一下函數(shù)如下:

import os
def readFileRight(file):
    if not os.path.exists(file):    
        print("文件不存在!---zz")
    else:
        try:
            readFile(file)
        except:
            print('讀取出錯啦?。?)

現(xiàn)在又有個糊涂蛋定義了writeFile(path)也是沒有做安全判斷,我們可以同樣使用上述方式繼續(xù)封裝函數(shù)。函數(shù)少我們可以這樣做,但試想下若有幾十個類似這樣的函數(shù),每一個函數(shù)都封裝一遍,en 。。敗類。 完全沒有我們程序猿的樣子(懶)。此時python的裝飾器就可以閃亮登場了。

裝飾器可以將函數(shù)a嵌入到函數(shù)b中

裝飾器也可以進一步封裝函數(shù),但是不像我們平常封裝函數(shù)一樣,同樣的功能需要對每個原函數(shù)都封裝一遍。麻煩。感受下裝飾器:

import os
def readFileRight(func):
    def wrapper(file):
        if not os.path.exists(file):    
            print("文件不存在!---zz")
        else:
            try:
                readFile(file)
            except:
                print('讀取出錯啦??!')
    return wrapper

@readFileRight            
def readFile(file):
    f = open(file, 'r', encoding="utf-8")
    for line in f.readlines():
        print(line)
    f.close()

file = 'hhh.txt'
readFile(file)

此時只需要定義一遍readFileRight() ,在后續(xù)的需要做安全檢查的函數(shù)前使用@readFileRight裝飾一下,現(xiàn)在調(diào)用函數(shù)的方式不變但函數(shù)'readFile()'已經(jīng)具備了安全檢查的功能。
即當我們有如下需求時可以使用裝飾器,也推薦使用裝飾器:

@1.使用別人的代碼時,某個功能不能滿足自己的需求,盡量別動別人的源碼
@2.相同的功能在大量的函數(shù)前需要被添加

裝飾器由簡到難

注:hh()為原始函數(shù),log()為裝飾器函數(shù)

裝飾 無參函數(shù):hh() = log(hh)()

def log(func):
    def wrapper():
        print("start -------")
        func()
        print("end ------")
    return wrapper

@log
def hh():
    print("hhhhhhhhhhh")
    
hh()

輸出:
start -------
hhhhhhhhhhh
end ------

使用@log裝飾函數(shù)hh 其實是執(zhí)行了 hh = log(hh) 得到 hh = wrapper
即改變了hh變量所指向的函數(shù)。而原來的函數(shù)當做參數(shù)傳到了wrapper中,所以當我們執(zhí)行hh()時實際上是執(zhí)行了wrapper()。此處在函數(shù)中又定義了函數(shù),并返回函數(shù),需要我們知道2個知識點 python 的閉包 以及 python中一切皆對象,函數(shù)也是對象

裝飾 有參函數(shù):hh(*args) = log(hh)(*args)

def log(func):
    def wrapper(*args,**kwargs):
        print("start -------")
        func(*args, **kwargs)
        print("end ------")
    return wrapper

@log
def hh(info):
    print(info)
    
hh(r"i'm ok")

輸出:
start -------
i'm ok
end ------

使用@log裝飾函數(shù)hh(info) 其實是執(zhí)行了 hh = log(hh) 得到 hh(info) = wrapper(info) ,所以當我們執(zhí)行hh(info)時實際上是執(zhí)行了wrapper(info)。此處函數(shù)wrapper(*args, **kwargs)表示可以接受任意參數(shù),一般情況下該模式都可以,但是在一些特殊情況下:在原函數(shù)外部需要使用函數(shù)的參數(shù)時,會需要明確指明函數(shù)的傳參情況,后面我們講裝飾類函數(shù)時會遇到

帶參裝飾器: hh() = log(text)(hh)()

import time
def log(text):
    def decorator(func):
        def wrapper():
            print('開始時間---%s' %text )
            print("start -------")
            func()
            print("end ------")
        return wrapper
    return decorator

text = time.time()
@log(text)
def hh():
    print('hhhhhhhh')

輸出:
開始時間---1533918264.889485
start -------
i'm ok
end ------

使用@log(text)裝飾函數(shù)hh() 其實是執(zhí)行了 hh = log(text)(hh) 得到 hh = decorator(hh) ,進一步裝飾得到hh = wrapper 所以當我們執(zhí)行hh()時實際上是執(zhí)行了wrapper()。而此時原函數(shù)hh()以及參數(shù)text也通過裝飾的過程將內(nèi)容傳入了wrapper()中。該裝飾模式可以使用在程序運行的過程中,我們可以動態(tài)的傳入需要的參數(shù)。自己探索:hh(info) = log(text)(hh)(info)

總結(jié)

記住4中裝飾模式,了解本質(zhì)既就算再復雜我們也可以一點點拆解
@1.裝飾 無參函數(shù):hh() = log(hh)()
@2.裝飾 有參函數(shù):hh(*args) = log(hh)(*args)
@3.帶參裝飾器裝飾無參函數(shù): hh() = log(text)(hh)()
@4.帶參裝飾器裝飾有參函數(shù): hh(*args) = log(text)(hh)(*args)

提前預告

下一篇:Python 裝飾器 續(xù)集
會更加深入的分析裝飾器的原理。即擴展裝飾器的用途。期待吧!!

注:

該文章中的很多名詞都是我自己的叫法。比如:裝飾無參函數(shù),這些都是為了利于分析講解,正規(guī)叫法我也不太清除,還有本人也是python小白一枚,如果上面的分析有誤,歡迎大家指正,一起學習,謝謝~~

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 一.函數(shù)裝飾器 1.從Python內(nèi)層函數(shù)說起 首先我們來探討一下這篇文章所講的內(nèi)容Inner Functions...
    軟體動物Ai閱讀 3,380評論 0 14
  • 每個人都有的內(nèi)褲主要功能是用來遮羞,但是到了冬天它沒法為我們防風御寒,咋辦?我們想到的一個辦法就是把內(nèi)褲改造一下,...
    chen_000閱讀 1,403評論 0 3
  • Python 中的函數(shù)和 Java、C++不太一樣,Python 中的函數(shù)可以像普通變量一樣當做參數(shù)傳遞給另外一個...
    stoneyang94閱讀 1,426評論 1 4
  • 轉(zhuǎn)自Python之禪 講 Python 裝飾器前,我想先舉個例子,雖有點污,但跟裝飾器這個話題很貼切。每個人都有的...
    井底蛙蛙呱呱呱閱讀 228評論 2 0
  • ----裝飾器能對你所寫的代碼產(chǎn)生極大的正面作用 Python裝飾器是很容易使用的。任何一個會寫Python函數(shù)的...
    M耀文閱讀 612評論 0 1

友情鏈接更多精彩內(nèi)容