亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

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

系統(tǒng) 1728 0

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

以下說(shuō)明主要針對(duì) python2.7,其他版本可能存在差異。

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

            
def wai_hanshu(canshu_1):

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

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

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

我在函數(shù)里面有嵌套了一個(gè)函數(shù),當(dāng)我向外層函數(shù)傳遞一變量的之后,并賦值給 a ,我們發(fā)現(xiàn) a 變成了一個(gè)函數(shù)對(duì)象,而我再次為這個(gè)函數(shù)對(duì)象傳參的時(shí)候,又獲得了內(nèi)部函數(shù)的返回值。我們知道,按照作用域的原則來(lái)說(shuō),我們?cè)谌肿饔糜蚴遣荒茉L問(wèn)局部作用域的。但是,這里通過(guò)討巧的方法訪問(wèn)到了內(nèi)部函數(shù)。。

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

            
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)的原因,這里我簡(jiǎn)要說(shuō)明一下。

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

深入理解python中的閉包和裝飾器_第1張圖片

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

深入理解python中的閉包和裝飾器_第2張圖片

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

作用域的誕生,是因?yàn)楫?dāng)python在尋找一個(gè)變量的時(shí)候,首先會(huì)在當(dāng)前的命名空間中尋找,如果當(dāng)前命名空間中沒(méi)有,就到上一級(jí)的命名空間中找,以此類推,如果最后都沒(méi)找到,則觸發(fā)變量沒(méi)找到的異常。

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

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

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

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

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

  return nei_hanshu

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

深入理解python中的閉包和裝飾器_第3張圖片

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

裝飾器

其實(shí)裝飾器就是在閉包的基礎(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()   # 此時(shí)執(zhí)行的就是被裝飾后的函數(shù)了
          

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

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

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

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

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

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

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

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


login()
          

這些小便利也叫做python的語(yǔ)法糖,你可能在很多地方見過(guò)這個(gè)說(shuō)法。

帶參數(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)行了登錄功能'
          

深入理解python中的閉包和裝飾器_第4張圖片

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

裝飾器的嵌套:

這里就不完整寫個(gè)例子了:

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

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

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

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

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


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 麻豆国产高清精品国在线 | 激情五月色婷婷在线观看 | 波多野结衣一二三区 | 一级a做爰片欧欧美毛片4 | 美女久久精品 | 玖玖国产| 亚洲va天堂va国产va久 | 亚洲成人在线观看视频 | 欧美18videosex灌满 | 久久精品国产精品亚洲婷婷 | 四虎影院国产精品 | 精品国产一区二区三区四区不 | 国产男女爱视频在线观看 | 97视频精品 | 五月天婷婷在线播放 | 日本一二区视频 | www.黄色一片| 久久怡红院国产精品 | 国产一区二区三区高清 | 久草在线中文视频 | 你懂得国产| 亚洲精品美女在线观看 | 女人18毛片a级毛片免费视频 | 久久综合亚洲一区二区三区 | 一区二区三区四区亚洲 | 色天使色婷婷在线影院亚洲 | 成人网久久 | 免费看欧美一级a毛片 | 国产精品久久久久久久成人午夜 | 久草手机视频在线 | 国产一区二区三区不卡观 | 欧美成人手机在线视频 | 日韩欧美亚洲国产精品字幕久久久 | 国产在线视频www色 国产在线视频凹凸分类 | 亚洲国产爱久久全部精品 | 99影视在线视频免费观看 | 一级毛片中文字幕 | 亚洲一区 欧美 | 亚洲在线网站 | 五月天激情亚洲婷婷在线 | 韩国一级理黄论片 |