久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Python裝飾器1-閉包與函數(shù)裝飾器

 網(wǎng)摘文苑 2023-02-16 發(fā)布于新疆

一,、閉包

在學(xué)習(xí)裝飾器前,,需要先了解閉包的概念。形成閉包的要點(diǎn):

  • 函數(shù)嵌套
  • 將內(nèi)部函數(shù)作為外部函數(shù)的返回值
  • 內(nèi)部函數(shù)必須要使用到外部函數(shù)的變量

下面以一個(gè)計(jì)算列表平均值的案例來講解閉包:

def make_average(): # 創(chuàng)建一個(gè)列表,,用來保存數(shù)值 nums = [] # 定義一個(gè)內(nèi)部函數(shù),,用來計(jì)算列表的平均值 def average(n): # 將數(shù)值添加到列表中 nums.append(n) # 返回平均值 return sum(nums) / len(nums) return average
  1. 首先,定義一個(gè)函數(shù)make_average,;
  2. 其次,,在make_average函數(shù)內(nèi)定義一個(gè)空列表,用來存儲(chǔ)數(shù)值,;
  3. 再次,,定義一個(gè)內(nèi)部函數(shù),用來計(jì)算列表平均值,;
  4. 最后,,將這個(gè)內(nèi)函數(shù)作為外函數(shù)make_average的返回值,注意不要加( ),,加( )就變成調(diào)用這個(gè)函數(shù)了,。
# 調(diào)用外部函數(shù),并將其復(fù)制給一個(gè)變量,,注意:此時(shí)返回的是內(nèi)函數(shù)的內(nèi)存地址a = make_average()# 給這個(gè)變量加(),,就相當(dāng)于調(diào)用了內(nèi)函數(shù)averageprint(a(20))print(a(30))

運(yùn)行結(jié)果如下:當(dāng)傳入的數(shù)值為20時(shí),列表中只有一個(gè)數(shù),,所以計(jì)算結(jié)果是20,;當(dāng)再傳入一個(gè)數(shù)值30時(shí),,此時(shí)列表中就有兩個(gè)數(shù)20和30,所以平均值的計(jì)算結(jié)果是25.

文章圖片1

二,、裝飾器

1.裝飾器引入

例如,,有以下兩個(gè)函數(shù),分別計(jì)算兩個(gè)數(shù)的和以及成績(jī):

def add(a, b): '''計(jì)算兩數(shù)之和''' res = a + b return resdef mul(a, b): '''計(jì)算兩數(shù)之積''' res = a * b return res

現(xiàn)在有個(gè)需求:我想要在每個(gè)函數(shù)的計(jì)算開始前打印“開始計(jì)算...”,,在計(jì)算結(jié)束后打印“計(jì)算結(jié)束...”,。我們可以通過直接修改函數(shù)代碼的方式來滿足這個(gè)需求,,但這樣會(huì)面臨以下問題:

  1. 如果要修改的函數(shù)過多,,十個(gè)甚至一百個(gè)函數(shù),未免不現(xiàn)實(shí),;
  2. 不便于后期維護(hù),,例如我不想打印“開始計(jì)算...”了,而是要打印“begin...”,,豈不是又要重新修改一遍,;
  3. 違反開閉原則(OCP),即程序的設(shè)計(jì),,要求開放對(duì)程序的擴(kuò)展,、關(guān)閉對(duì)程序的修改;

所以,,上述直接修改函數(shù)代碼的方式不可行,。我們希望在不修改原函數(shù)的情況下,實(shí)現(xiàn)對(duì)函數(shù)的擴(kuò)展,。例如:

def new_add(a, b):    print('開始計(jì)算...')    r = add(a, b)    print('計(jì)算結(jié)束...')    return rprint(new_add(22, 33))

執(zhí)行結(jié)果如下:

文章圖片2

這種新創(chuàng)建一個(gè)函數(shù)的方式雖然沒有修改原函數(shù),,但面臨一個(gè)很嚴(yán)重的問題:

只能擴(kuò)展指定函數(shù),不能通用于其它函數(shù),,例如擴(kuò)展上述的add函數(shù),,而不能擴(kuò)展mul函數(shù),如果想要擴(kuò)展mul函數(shù),,只能再創(chuàng)建一個(gè)擴(kuò)展函數(shù),;

因?yàn)椋覀兿M梢远x一個(gè)通用的擴(kuò)展函數(shù),,可以作用域所有函數(shù),。這類不改變?cè)瘮?shù)代碼的通用函數(shù)就是:裝飾器

2.函數(shù)裝飾器

裝飾器本質(zhì)上是一個(gè)python函數(shù)或類,,它可以讓其他函數(shù)或類在不需要做任何代碼修改的前提下增加額外功能,,也就是為已經(jīng)存在的對(duì)象添加額外功能,裝飾器的返回值也是一個(gè)函數(shù)/類對(duì)象,。它經(jīng)常用于有切面需求的場(chǎng)景,,比如:插入日志、性能測(cè)試、事務(wù)處理,、緩存,、權(quán)限校驗(yàn)等場(chǎng)景。

1)被裝飾函數(shù)不帶參數(shù)

例如:

def wrapper_info(func): def inner(): print('開始介紹...') res = func() print('介紹結(jié)束...') return res return innerdef introduce1(): print('我是周潤(rùn)發(fā),,我來自HONG KONG')info = wrapper_info(introduce1)info()

運(yùn)行結(jié)果如下:

文章圖片3

可見,,在沒有改變?cè)瘮?shù)代碼的情況下,即給原函數(shù)增加了一些額外的功能,,func是要修飾的函數(shù),,作為一個(gè)變量傳入裝飾函數(shù),能夠通用于其他函數(shù),,這個(gè)wrapper_info就是裝飾器,。但目前面臨的問題是,被裝飾函數(shù)如果帶參數(shù)怎么辦,?例如:

def introduce2(name, age):    print(f'我叫{name}, 我今年{age}歲了')

2)被裝飾函數(shù)帶參數(shù)

盡管可以在裝飾器wrapper_info中傳入name,、age,但并不是每個(gè)被裝飾的函數(shù)都只有name,、age,,亦或是指定類型的參數(shù),還有可能傳入的是字典,、列表,、元組等。也就是傳入?yún)?shù)的類型和數(shù)量不固定怎么辦,?

此時(shí)就需要用到不定長(zhǎng)參數(shù):(*args, **kwargs)

def wrapper_info(func): ''' 用來對(duì)其他函數(shù)進(jìn)行擴(kuò)展,,使其他函數(shù)可以在執(zhí)行前做一些額外的動(dòng)作 :param func: 要擴(kuò)展的函數(shù)對(duì)象 :return: ''' def inner(*args, **kwargs): print('開始介紹...') res = func(*args, **kwargs) print('介紹結(jié)束...') return res return inner

例如:

def introduce3(name, age, city):    print(f'我叫{name}, 我今年{age}歲了, 我來自{city}')

運(yùn)行結(jié)果如下:

文章圖片4

3)裝飾器帶參數(shù)

上述提到的是裝飾器,一種是應(yīng)用于被裝飾的函數(shù)不帶參數(shù),,一種是被裝飾的函數(shù)帶參數(shù),,那裝飾器本身能否帶參數(shù)呢?比如我定義一個(gè)變量,,想通過傳入不同的值來控制這個(gè)裝飾器實(shí)現(xiàn)不同的功能,。答案是肯定的,例如:

def use_log(level): def decorator(func): def inner(*args, **kwargs): if level == 'warn': logging.warning('%s is running by warning' % func.__name__) elif level == 'info': logging.warning('%s is running by info' % func.__name__) else: logging.warning('%s is running by other' % func.__name__) return func(*args, **kwargs) return inner return decoratordef introduce4(name, age, city): print(f'我叫{name}, 我今年{age}歲了, 我來自{city}')info1 = use_log(introduce4('周星馳', 28, '香港'))info1('info')info2 = use_log(introduce4('周潤(rùn)發(fā)', 28, '香港'))info2('warn')info3 = use_log(introduce4('成龍', 28, '香港'))info3('xxx')

運(yùn)行結(jié)果如下:

文章圖片5

3.裝飾器調(diào)用

方式一:以函數(shù)方式調(diào)用

info3 = wrapper_info(introduce3)info3('劉德華', 28, '香港')

如果是裝飾器函數(shù)帶參數(shù),,則調(diào)用方式為:

info4 = use_log(introduce4('周星馳', 28, '香港'))info4('info')

方式二:以語法糖方式調(diào)用

即在被裝飾函數(shù)上方以@符號(hào)進(jìn)行修飾

@wrapper_infodef introduce3(name, age, city):    print(f'我叫{name}, 我今年{age}歲了, 我來自{city}')introduce3('劉德華', 28, '香港')

如果是裝飾器函數(shù)帶參數(shù),,例如上述的use_log,則需要在裝飾器中傳入?yún)?shù):

@use_log('info')def introduce4(name, age, city): print(f'我叫{name}, 我今年{age}歲了, 我來自{city}')

小結(jié)

什么是裝飾器,?

在不改變?cè)瘮?shù)代碼的情況下,,給原函數(shù)增加了一些額外的功能,并且能夠通用于其他函數(shù),,這樣的函數(shù)就稱作為裝飾器,。

裝飾器的調(diào)用

可以通過傳統(tǒng)調(diào)用函數(shù)的方式進(jìn)行調(diào)用,,也可以通過@裝飾器的方式調(diào)用

裝飾器的特點(diǎn)

  • 通過裝飾器,可以在不修改原來函數(shù)的情況下對(duì)函數(shù)進(jìn)行擴(kuò)展
  • 一個(gè)函數(shù)可以同時(shí)指定多個(gè)裝飾器

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多