日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Python的幾個高級語法概念淺析(lambda表達式閉包裝飾器)

系統 1664 0

1. 匿名函數
匿名函數(anonymous function)是指未與任何標識符綁定的函數,多用在functional programming languages領域,典型應用場合:
1) 作為參數傳給高階函數(higher-order function ),如python中的built-in函數filter/map/reduce都是典型的高階函數
2) 作為高階函數的返回值(雖然此處的"值"實際上是個函數對象)
與命名函數(named function)相比,若函數只被調用1次或有限次,則匿名函數在語法上更輕量級。
具體語法上,python通過lambda語法支持函數體為表達式的匿名函數,即:python的lambda表達式本質上是個匿名函數,但其函數體只能是個表達式,不能包含其它語句。
此外,高級動態語言常借助匿名函數實現閉包(closure)或裝飾器(decorator)等高級語法。
在一些場合下,lambda表達式的使用使得python程序看起來非常簡潔。例如,下面是根據value對dict元素做排序的代碼示例:

          
>>> foo = {'father' : 65, 'mother' : 62, 'sister' : 38, 'brother' : 29, 'me' : 28}
>>> sorted(foo.iteritems(), key=lambda x: x[1])
[('me', 28), ('brother', 29), ('sister', 38), ('mother', 62), ('father', 65)]
        

2. 閉包
閉包(closure)本質上是一個包含了其引用環境(referencing environment)的函數或函數引用,這里的"引用環境"通常由一張表來維護,該表存儲了函數體會訪問的非局部變量(non-local variables)的引用。
與C語言中的函數指針相比,閉包允許嵌套函數訪問其作用域外的non-local變量,這與Python解釋器對變量的作用域查找規則有關(Python支持LEGB的查找規則,想深究的話,可以參考 第4版第17章Scopes關于作用域及查找規則的詳細講解,或者查看這篇文章 做快速了解)。
對于運行時內存分配模型會在線性棧上創建局部變量的語言來說(典型如C語言),通常很難支持閉包。因為這些語言底層實現中,若函數返回,則函數中定義的局部變量均會隨著函數棧被回收而銷毀。但閉包在底層實現上要求其要訪問的non-local變量在閉包被執行的時候保持有效,直到這個閉包的生命周期結束,這意外著這些non-local變量只有在其確定不再被使用時才能銷毀,而不能隨著定義這些變量的函數返回銷毀。因此, 天生支持閉包的語言通常采用garbage collection的方式管理內存,因為gc機制保證了變量只有不再被引用時才會 由系統銷毀并回收其內存空間
具體語法上,閉包通常伴隨著函數嵌套定義。以Python為例,一個簡單的閉包示例如下:

          
#!/bin/env python
#-*- encoding: utf-8 -*-

def startAt_v1(x):
 def incrementBy(y):
  return x + y 
 print 'id(incrementBy)=%s' % (id(incrementBy))
 return incrementBy

def startAt_v2(x):
 return lambda y: x + y 

if '__main__' == __name__:
 c1 = startAt_v1(2)
 print 'type(c1)=%s, c1(3)=%s' % (type(c1), c1(3))
 print 'id(c1)=%s' % (id(c1))
 
 c2 = startAt_v2(2)
 print 'type(c2)=%s, c2(3)=%s' % (type(c2), c2(3))
        

執行結果如下:

          
id(incrementBy)=139730510519782
type(c1)=
          
            , c1(3)=5
id(c1)=139730510519782
type(c2)=
            
              , c2(3)=5
            
          
        

上述示例中,startAt_v1和startAt_v2均實現了閉包,其中:v1借助嵌套定義函數實現;v2則借助lambda表達式/匿名函數來實現。
我們以v1為例對閉包做說明:
1) 函數startAt_v1接受1個參數,返回1個函數對象,而這個函數對象的行為由嵌套定義的函數incrementBy實現。
2) 對函數incrementBy來說,變量x就是所謂的non-local變量(因為x既非該函數定義的局部變量,又非普通意義上的全局變量),incrementBy實現具體的函數行為并返回。
3) main入口的c1接收到的返回值是個函數對象,從id(incrementBy) == id(c1)可斷定,c1"指向"的對象與函數名incrementBy"指向"的其實是同一個函數對象。
4) 受益于Python對閉包的支持,與普通函數的對象相比,c1指向的對象可以訪問不在其函數作用域內的non-local變量,而這個變量是由incrementBy的外層包裝函數startAt_v1的入參提供的,于是,相當于c1指向的函數對象對其外層包裝函數的入參具有"記憶"功能,通過調用外層包裝函數創建閉包時,不同的入參被內層函數作為引用環境維護起來。
5) 調用c1(3)時,傳入的參數與引用環境維護的外層包裝函數的參數一起運算得到最終結果。
以上步驟分析說明了一個閉包從創建到執行的基本原理,理解這個case后,閉包的概念也應該清晰了。

3. 裝飾器
python支持裝飾器(decorator)語法。裝飾器的概念對于初學者來說比較晦澀,因為它涉及到函數式編程的幾個概念(如匿名函數、閉包),這也是本文先介紹匿名函數和閉包的原因。

我們引用這篇文章對裝飾器的定義:
A decorator is a function that takes a function object as an argument, and returns a function object as a return value.
從這個定義可知,裝飾器本質上只是一個函數,它借助閉包的語法去修改一個函數(又稱被裝飾函數)的行為,即decorator其實是個閉包函數,該函數以被裝飾函數名(這個函數名其實是一個函數對象的引用)作為入參,在閉包內修改被裝飾函數的行為后,返回一個新的函數對象。
特別說明: decorator并非必須以函數形式出現,它可以是任何可被調用的對象,例如它也可以class形式出現,參見這篇文章給出的例子。
在定義好函數裝飾器的前提下,當外部調用這個被裝飾函數時,decorator的語法糖會由Python解釋器解釋為先執行裝飾器函數,然后在裝飾器返回的新函數對象上繼續執行其余語句。
來個實例分析一下:

          
#!/bin/env python
#-*- encoding: utf-8 -*-

def wrapper(fn):
 def inner(n, m):
  n += 1
  print 'in inner: fn=%s, n=%s, m=%s' % (fn.__name__, n, m)
  return fn(n, m) + 6 // 這里有return且返回值為int對象
 return inner

@wrapper
def foo(n, m):
 print 'in foo: n=%s, m=%s' % (n, m)
 return n * m

print foo(2, 3)
        

上面的示例中,foo通過@wrapper語法糖聲明它的裝飾器是wrapper,在wrapper中,定義了嵌套的inner函數(該函數的參數列表必須與被裝飾函數foo的參數列表保持一致),裝飾器wrapper修改foo的行為后,返回inner(注意:由于inner的返回值是個int對象,故wrpper最終返回的也是個int對象)。
調用foo(2, 3)時,Python解釋器先調用wrapper對foo做行為改寫,然后返回int對象,不難推測,上述代碼的執行結果如下:

          
in inner: fn=foo, n=3, m=3
in foo: n=3, m=3
foo(2, 3)=15
        

更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 清水县| 荥经县| 休宁县| 三明市| 昆明市| 宣汉县| 会东县| 公主岭市| 华安县| 克山县| 乌拉特后旗| 秦皇岛市| 合山市| 哈密市| 武冈市| 昌黎县| 毕节市| 临潭县| 乌拉特中旗| 华宁县| 新乐市| 新建县| 习水县| 镇巴县| 辽阳县| 石屏县| 新干县| 秀山| 南漳县| 区。| 彰化县| 霍城县| 富顺县| 临清市| 浙江省| 锦州市| 安化县| 丹东市| 五华县| 肥东县| 灵台县|