python學(xué)習(xí)繞不過的函數(shù)裝飾器

  • 概念:類似于將函數(shù)包裹起來溜腐,實(shí)現(xiàn)同一功能的函數(shù)
  • 功能:在代碼運(yùn)行期間動(dòng)態(tài)增加功能的方式

一党觅、知識(shí)準(zhǔn)備

  • 理解python中 *args 和 **kwargs
# 測(cè)試函數(shù)
def test_args_kwargs(arg1,arg2,arg3):
    print("arg1:",arg1)
    print("arg2:",arg2)
    print("arg3P:",arg3)
# 使用*args
args = ("two",3,5)
test_args_kwargs(*args)
# 使用 **kwargs
kwargs = {"arg3":5,"arg1":two,"arg2":3}
test_args_kwargs(**kwargs)
# 可以同時(shí)使用,但應(yīng)注意順序
  • python 中的函數(shù)名稱也是對(duì)象(一切皆對(duì)象)
def hi(name):
    print("hi! ",name)
# 使用函數(shù)名作為變量
welcom = hi
welcom("xiaoming")
  • 在函數(shù)中定義函數(shù)
def hi(name='wangweiyang'):
    print("now you are in insdie the hi() function")
    # 定義內(nèi)部函數(shù)
    def greet()
        print("now you are in the greet() function")
    def welcome()
        print("now you are in the welcome() function")
hi()
# 內(nèi)部函數(shù)在外部是不能直接訪問的
>>> greet() 錯(cuò)誤
  • 從函數(shù)中返回函數(shù)
def hi(name='wangweiyang'):
    def greet():
        return "now you are in the greet() function"
    def welcome():
        return "now you are in the welcome() function"
    if name == "wangweiyang":
        return greet
    else:
        return welcome
a = hi()
print(a)
print(a())
  • 將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)
def hi():
    return "hi!wangweiyang!"
def doSomethingBeforeHi(func):
    print("Do something before executing hi()")
    print(func())
doSomethingBeforeHi(hi)
  • 創(chuàng)建第一個(gè)裝飾器
# 裝飾函數(shù)
def a_new_decorator(a_func):
    def wrapTheFunction():
        print("Do some work before executing a_func()")
        a_func()
        print("Do some work after executing a_func()")
    return wrapTheFunction
# 被裝飾的函數(shù)
def a_function_requiring_decoration():
    print("The function which needs some decoration to remove or add something")
# 裝飾過程    
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
# 裝飾結(jié)果
a_function_requiring_decoration()
  • 閉包

二褒纲、創(chuàng)建裝飾器

  • 使用@符號(hào):本質(zhì)上就是裝飾過程(簡(jiǎn)化與統(tǒng)一)
# 裝飾函數(shù)
def a_new_decorator(a_func):
    def wrapTheFunction():
        print("Do some work before executing a_func()")
        a_func()
        print("Do some work after executing a_func()")
    return wrapTheFunction
# 使用@符號(hào)進(jìn)行裝飾
@a_new_decorator
def a_function_requiring_decoration():
    """
    Please decorate me!
    """
    print("The function which needs some decoration to remove or add something")
# 裝飾結(jié)果
a_function_requiring_decoration()   
  • 使用裝飾器會(huì)覆蓋掉(重寫)原函數(shù)本身的一些函數(shù)屬性
# 輸出函數(shù)本身名稱
print(a_function_requiring_decoration.__name__)
# output:wrapTheFuction()
print(a_function_requiring_decoration.__doc__)
# output:None
  • 使用functools.wraps來解決函數(shù)屬性的問題
# 引入wraps
from functools import wraps
# 裝飾函數(shù)
def a_new_decorator(a_func):
    @wraps(a_func)
    # 使用wraps
    def wrapTheFunction():
        print("Do some work before executing a_func()")
        a_func()
        print("Do some work after executing a_func()")
    return wrapTheFunction
# 使用@符號(hào)進(jìn)行裝飾
@a_new_decorator
def a_function_requiring_decoration():
    """
    Please decorate me!
    """
    print("The function which needs some decoration to remove or add something")
# 裝飾結(jié)果
a_function_requiring_decoration() 
print(a_function_requiring_decoration.__name__)
# output: a_function_requiring_decoration

三楼雹、裝飾器的使用場(chǎng)景

  • 授權(quán)(Authorization)-Django與Flask框架
from functools import wraps
def requires_auth(f):
    @wraps(f)
    def decorated(*args,**kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username,auth.password):
            authenticate()
        return f(*args,**kwargs)
    return decorated
  • 日志(Logging)
from functools import wraps
def logit(func):
    @wraps(func)
    def with_logging(*args,**kwargs):
        print(func.__name__ + "was called")
        return func(*args,**kwargs)
    return with_logging
@logit
def addition_func(x):
    """Do some math"""
    return x+x
result = addition_func(4)
# Output:addition_func was called

四脐雪、裝飾器進(jìn)階

  • 在函數(shù)中嵌入裝飾器(可以接收函數(shù)的裝飾器)
from functools import wraps
def logit(logfile="out.log"):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args,**kwargs):
            log_string = func.__name__ + "was called"
            print(log_string)
            # 打開logfile,并寫入內(nèi)容
            with open(logfile,"a") as opend_file:
                # 將日志寫入指定的logfile
                opend_file.write(log_string + "\n")
            return func(*args,**kwargs)
        return wrapped_function
    return logging_decorator
@logit
def myfunc1():
    pass
myfunc1()
@logit(logfile='func2.log')
def myfunc2():
    pass
myfunc2
  • 裝飾器類
from functools import wraps
class logit(object):
    def __init__(self,logfile='out.log'):
        self.logfile = logfile
    def __call__(self,func):
        @wraps(func)
        def wrapper_function(*args,**kwargs):
            log_string = func.__name__ + "was called"
            print(log_string)
            # 打開logfile并寫入
            with open(self.logfile,'a') as opend_file:
                # 將日志寫入指定的文件
                opened_file.write(log_string + '\n')
            # 發(fā)送一個(gè)通知
            self.notify()
            return func(*args,**kwargs)
        return wrappend_function
    def notify(self):
        # logit只打開日志
        pass
@logit()
def myfunc1():
    pass
class email_logit(logit):
    """
    一個(gè)logit的實(shí)現(xiàn)版本筛欢,可以在函數(shù)調(diào)用時(shí)發(fā)送email給管理員
    """
    def __init__(self,email="xxx@qq.com",*args,**kwargs):
        self.email = email
        super(email_logit,self).__init__(*args,**kwargs)
    def notify(self):
        # 發(fā)送一封郵件給管理員
        pass
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末浸锨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子版姑,更是在濱河造成了極大的恐慌柱搜,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剥险,死亡現(xiàn)場(chǎng)離奇詭異聪蘸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)表制,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門健爬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人么介,你說我怎么就攤上這事浑劳。” “怎么了夭拌?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵魔熏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我鸽扁,道長(zhǎng)蒜绽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任桶现,我火速辦了婚禮躲雅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘骡和。我一直安慰自己相赁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布慰于。 她就那樣靜靜地躺著钮科,像睡著了一般。 火紅的嫁衣襯著肌膚如雪婆赠。 梳的紋絲不亂的頭發(fā)上绵脯,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼蛆挫。 笑死赃承,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的悴侵。 我是一名探鬼主播瞧剖,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼可免!你這毒婦竟也來了抓于?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤巴元,失蹤者是張志新(化名)和其女友劉穎毡咏,沒想到半個(gè)月后驮宴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逮刨,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年堵泽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了修己。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡迎罗,死狀恐怖睬愤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纹安,我是刑警寧澤尤辱,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站厢岂,受9級(jí)特大地震影響光督,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜塔粒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一结借、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧卒茬,春花似錦船老、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至郭赐,卻和暖如春荸镊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工躬存, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留张惹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓岭洲,卻偏偏與公主長(zhǎng)得像宛逗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盾剩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容