亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入理解python中的閉包和裝飾器

 更新時間:2016年06月12日 15:09:57   投稿:jingxian  
下面小編就為大家?guī)硪黄钊肜斫鈖ython中的閉包和裝飾器。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

python中的閉包從表現(xiàn)形式上定義(解釋)為:如果在一個內(nèi)部函數(shù)里,對在外部作用域(但不是在全局作用域)的變量進(jìn)行引用,那么內(nèi)部函數(shù)就被認(rèn)為是閉包(closure)。

以下說明主要針對 python2.7,其他版本可能存在差異。

也許直接看定義并不太能明白,下面我們先來看一下什么叫做內(nèi)部函數(shù):

def wai_hanshu(canshu_1):

  def nei_hanshu(canshu_2): # 我在函數(shù)內(nèi)部有定義了一個函數(shù)
    return canshu_1*canshu_2

  return nei_hanshu  # 我將內(nèi)部函數(shù)返回出去

a = wai_hanshu(123)   # 此時 canshu_1 = 123
print a
print a(321)  # canshu_2 = 321

我在函數(shù)里面有嵌套了一個函數(shù),當(dāng)我向外層函數(shù)傳遞一變量的之后,并賦值給 a ,我們發(fā)現(xiàn) a 變成了一個函數(shù)對象,而我再次為這個函數(shù)對象傳參的時候,又獲得了內(nèi)部函數(shù)的返回值。我們知道,按照作用域的原則來說,我們在全局作用域是不能訪問局部作用域的。但是,這里通過討巧的方法訪問到了內(nèi)部函數(shù)。。

下面我們繼續(xù)看一個例子:

def wai_hanshu():
  a = []
  def nei_hanshu(canshu):
    a.append(canshu)
    return a

  return nei_hanshu

a = wai_hanshu()
print a(123)
print a(321)

可以看出函數(shù)位于外部函數(shù)中的列表 a 竟然改變了。要知道為什么,就要先知道什么是python的命名空間,而命名空間就是作用域表現(xiàn)的原因,這里我簡要說明一下。

引入命名空間的主要原因還是為了避免變量沖突,因為python中的模塊眾多,模塊中又有函數(shù),類等,它們都要使用到變量。但如果每次都要注意不和其他變量名沖突,那就太麻煩了,開發(fā)人員應(yīng)該專注于自己的問題,而不是考慮別人寫的程序中用到了什么變量,所以python引入了命名空間。命名空間分為模塊層,模塊內(nèi)又分為全局作用域和局部作用域,用一個圖來表示的話:

模塊之間命名空間不同,而里面還有全局作用域和局部作用域,局部作用域之前還能嵌套,這樣就能保證變量名不沖突了。這里順便補充一下,可以通過 __name__ 屬性獲取命名空間的名字:

主文件的命名空間是叫做 '__main__',而模塊的命名空間就是模塊名。

作用域的誕生,是因為當(dāng)python在尋找一個變量的時候,首先會在當(dāng)前的命名空間中尋找,如果當(dāng)前命名空間中沒有,就到上一級的命名空間中找,以此類推,如果最后都沒找到,則觸發(fā)變量沒找到的異常。

我們之前一直說:全局作用域無法訪問局部作用域,而局部作用域能夠訪問全局作用域就這這個原因。而當(dāng)我在局部作用域創(chuàng)建了一個和外面同名的變量時,python在找這個變量的時候首先會在當(dāng)前作用域中找,找到了,就不繼續(xù)往上一級找了。

在早期的python版本時,局部作用域是不能訪問其他的局部作用域的,只能訪問全局的,而現(xiàn)在的版本都是依次向上一級找,這里就提一下。

也就是因為這個特性,我們可以在內(nèi)部函數(shù)中訪問外部函數(shù)中的變量,這也就是所謂的閉包了。

注意:這里要做好對象之間的區(qū)分,例如:

def wai_hanshu():
  a = []
  def nei_hanshu(canshu):
    a.append(canshu)
    return a

  return nei_hanshu

a = wai_hanshu()  # 我創(chuàng)建了一個對象
b = wai_hanshu()  # 我又創(chuàng)建了一個對象
print a
print b
print a(123)
print b(321)

在這里,我們雖然都是操作 wai_hanshu 中的變量,但是 a 和 b 完全是兩個對象,它們所在的內(nèi)存空間也是不同的,所以里面的數(shù)據(jù)也是獨立的。要注意不要搞混。

裝飾器

其實裝飾器就是在閉包的基礎(chǔ)上多進(jìn)行了幾步,看代碼:

def zsq(func): # 裝飾函數(shù)
  def nei():
    print '我在傳入的函數(shù)執(zhí)行之前做一些操作'
    func() # 執(zhí)行函數(shù)
    print '我在目標(biāo)函數(shù)執(zhí)行后再做一些事情'
  return nei

def login():  # 被裝飾函數(shù)
  print '我進(jìn)行了登錄功能'

login = zsq(login)  # 我將被裝飾的函數(shù)傳入裝飾函數(shù)中,并覆蓋了原函數(shù)的入口

login()   # 此時執(zhí)行的就是被裝飾后的函數(shù)了

在看這段代碼的時候,要知道幾件事:

1.函數(shù)的參數(shù)傳遞的其實是引用,而不是值。

2.函數(shù)名也是一個變量,所以可以重新賦值。

3.賦值操作的時候,先執(zhí)行等號右邊的。

只有明白了上面這些事之后,再結(jié)合一下代碼,應(yīng)該就能明白什么是裝飾器了。所謂裝飾器就是在閉包的基礎(chǔ)上傳遞了一個函數(shù),然后覆蓋原來函數(shù)的執(zhí)行入口,以后調(diào)用這個函數(shù)的時候,就可以額外實現(xiàn)一些功能了。裝飾器的存在主要是為了不修改原函數(shù)的代碼,也不修改其他調(diào)用這個函數(shù)的代碼,就能實現(xiàn)功能的拓展。

而python覺得讓你每次都進(jìn)行重命名操作實在太不方便,于是就給出了一個便利的寫法:

def zsq(func):
  def nei():
    print '我在傳入的函數(shù)執(zhí)行之前做一些操作'
    func() # 執(zhí)行函數(shù)
    print '我在目標(biāo)函數(shù)執(zhí)行后再做一些事情'
  return nei

@zsq  # 自動將其下面的函數(shù)作為參數(shù)傳到裝飾函數(shù)中去
def login():
  print '我進(jìn)行了登錄功能'


login()

這些小便利也叫做python的語法糖,你可能在很多地方見過這個說法。

帶參數(shù)的裝飾器:

def zsq(a):
  print '我是裝飾器的參數(shù)', a
  def nei(func):
    print '我在傳入的函數(shù)執(zhí)行之前做一些操作'
    func() # 執(zhí)行函數(shù)
    print '我在目標(biāo)函數(shù)執(zhí)行后再做一些事情'
  return nei


@zsq('123')
def login():
  print '我進(jìn)行了登錄功能'

相當(dāng)于: login = zsq(123)(login) ,所以在這里沒有調(diào)用就執(zhí)行了。

裝飾器的嵌套:

這里就不完整寫個例子了:

@deco1(deco_arg) 
@deco2 
def func(): 
  pass

相當(dāng)于: func = deco1(deco_arg)(deco2(func)) 

也就是從上到下的嵌套了。

關(guān)于閉包和裝飾器就先講到這里,以后有需要再補充。

以上這篇深入理解python中的閉包和裝飾器就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Python內(nèi)存管理實例分析

    Python內(nèi)存管理實例分析

    這篇文章主要介紹了Python內(nèi)存管理,結(jié)合實例形式分析了Python對象的引用、垃圾回收、分配等相關(guān)原理與操作技巧,需要的朋友可以參考下
    2019-07-07
  • Python異常?ValueError的問題

    Python異常?ValueError的問題

    這篇文章主要介紹了Python異常?ValueError的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 基于Python實現(xiàn)簡單的人臉識別系統(tǒng)

    基于Python實現(xiàn)簡單的人臉識別系統(tǒng)

    這篇文章主要介紹了如何通過Python實現(xiàn)一個簡單的人臉識別系統(tǒng),文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Python有一定的幫助,感興趣的可以跟隨小編一起試一試
    2022-01-01
  • 淺談pandas用groupby后對層級索引levels的處理方法

    淺談pandas用groupby后對層級索引levels的處理方法

    今天小編就為大家分享一篇淺談pandas用groupby后對層級索引levels的處理方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-11-11
  • Django 解決model 反向引用中的related_name問題

    Django 解決model 反向引用中的related_name問題

    這篇文章主要介紹了Django 解決model 反向引用中的related_name問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • Python常用外部指令執(zhí)行代碼實例

    Python常用外部指令執(zhí)行代碼實例

    這篇文章主要介紹了Python常用外部指令執(zhí)行代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • LyScript實現(xiàn)內(nèi)存交換與差異對比的方法詳解

    LyScript實現(xiàn)內(nèi)存交換與差異對比的方法詳解

    LyScript?針對內(nèi)存讀寫函數(shù)的封裝功能并不多,只提供了內(nèi)存讀取和內(nèi)存寫入函數(shù)的封裝,本篇文章將繼續(xù)對API進(jìn)行封裝,實現(xiàn)一些在軟件逆向分析中非常實用的功能,需要的可以參考一下
    2022-08-08
  • Python?設(shè)計模式中的創(chuàng)建型建造者模式

    Python?設(shè)計模式中的創(chuàng)建型建造者模式

    本文介紹Python設(shè)計模式中的創(chuàng)建型建造者模式,其表現(xiàn)為復(fù)雜對象的創(chuàng)建與表現(xiàn)相分離,這樣,同一個過程就有不同的表現(xiàn),想要創(chuàng)建一個由多個部分組成的對象,而且它的構(gòu)成需要一步接一步的完成。只有當(dāng)各個部分都完成了,這個對象才完整,下文相關(guān)自來哦,需要的朋友可以參考下
    2022-02-02
  • 基于Python實現(xiàn)ComicReaper漫畫自動爬取腳本過程解析

    基于Python實現(xiàn)ComicReaper漫畫自動爬取腳本過程解析

    這篇文章主要介紹了基于Python實現(xiàn)ComicReaper漫畫自動爬取腳本過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Python實現(xiàn)SMTP發(fā)送郵件詳細(xì)教程

    Python實現(xiàn)SMTP發(fā)送郵件詳細(xì)教程

    這篇文章主要為大家詳細(xì)介紹了Python實現(xiàn)SMTP發(fā)送郵件詳細(xì)教程,附SMTP郵件發(fā)送代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08

最新評論