一、匿名函數
-
匿名函數,即沒有名字的函數,在高階函數傳參時,使用?lambda?表達式,往往能簡化代碼
-
格式:lambda?參數列表 :?表達式? ? ??lambda x : x **2? ? ??foo = lambda x,y : (x+y)**2? ? ?foo(2,1)? –> 9
-
使用?lambda?關鍵字來定義匿名函數? ? ? 參數列表不需要小括號? ? ? 冒號是用來分割參數列表和表達式的? ? ? 不需要使用?return,表達式的值,就是匿名函數返回值? ? ? lambda?表達式(匿名函數)只能寫在一行上,被稱為單行函數
-
>>> (lambda x,y=3:x+y)(5,y=44)? ? ? ?–>? ?49? ? ??>>> (lambda x,*,y=30:x+y)(5,y=9)? ? –>? ?14? ? ??>>> print((lambda *args: [x+2 for x in args])(*range(5)))? ? –>? [2, 3, 4, 5, 6]? ? ??>>> [x for x in (lambda *args:map(lambda x:x+1,args))(*range(5))]? ? –>? [1, 2, 3, 4, 5]? ? ??>>> [x for x in (lambda *args:map(lambda x:(x+1,args),args))(*range(5))]? ? ? ? ? –>? ? [(1, (0, 1, 2, 3, 4)), (2, (0, 1, 2, 3, 4)), (3, (0, 1, 2, 3, 4)), (4, (0, 1, 2, 3, 4)), (5, (0, 1, 2, 3, 4))]
二、遞歸
-
函數直接或者間接調用自身就是遞歸? ? ?遞歸需要有邊界條件、遞歸前進段、遞歸返回段? ? ?遞歸一定要有邊界條件? ? ?當邊界條件不滿足的時候,遞歸前進? ? ?當邊界條件滿足的時候,遞歸返回
-
遞歸調用的深度不宜過深? ? ? ? ?Python?對遞歸調用的深度做了限制,以保護解釋器? ? ? ? ?超過遞歸深度限制,拋出?RecursionError: maxinum recursic depth exceeded?超出最大深度? ? ? ? ?查看遞歸深度? ? ? ? ?import sys? ? ? ? ?def fool(b,b1=3):? ? ? ??? ??? ?fool(b)? ? ? ? ?print(sys.getrecursionlimit())? ? ? ? ?sys.setrecursionlimit(2000)? ? 把遞歸深度改為 2000
-
遞歸的性能? ? ? ? ?循環稍微復雜一些,但是只要不是死循環,可以多次迭代直至算出結果? ? ? ? ?遞歸還有深度限制,如果遞歸復雜,函數反復壓棧,棧內存很快就溢出了
-
遞歸總結? ? ? ? ?遞歸是一種很自然的表達,符合邏輯思維? ? ? ? ?遞歸相對運行效率低,每一次調用函數都要開辟棧幀? ? ? ? ?遞歸有深度限制,如果遞歸層次太深,函數反復壓棧,棧內存很快就溢出了? ? ? ? ?如果是有限次數的遞歸,可以使用遞歸調用,或者使用循環代替,循環代碼稍微復雜一些,但是只要不是死循環,可以多次迭代直至算出結果? ? ? ? ?絕大多數遞歸,都可以使用循環實現? ? ? ? ?即使遞歸代碼很簡潔,但是能不用則不用遞歸
三、返回值和作用域
-
Python?函數使用?return?語句返回 “返回值”? ? ?所有函數都使用返回值,如果沒有?return?語句,隱式調用?return?None? ? ?return?語句并不一定是函數的語句塊的最后一條語句? ? ?一個函數可以存在多個?return?語句,但是只有一條可以被執行,如果沒有一條?return?語句被執行到,隱式調用?return?None? ? ?如果有必要,可以顯示調用?return?None,可以簡寫為?return? ? ?如果函數執行了?return?語句,函數就會返回,當前被執行的?return?語句之后的其它語句就不會被執行了? ? ? 作用:結束函數調用、返回值
-
函數不能同時返回多個值? ? ? return 1,3,5?看似返回多個值,隱式的被?Python?封裝成了一個元祖,然后順便可以用解構提取更方便
-
函數有可見范圍,這就是?作用域?的概念? ? ? 內部函數不能在外部直接使用,會拋出?NameError?異常,因為它不可見
-
一個標識符的可見范圍,這就是標識符的作用域,一般常說的是變量的作用域
-
全局作用域? ? ? ? ? ? 在整個程序運行環境中都可見? ? ? 局部作用域? ? ? ? ? ? 在函數、類等內部可見? ? ? ? ? ? 局部變量使用范圍不能超過其所在的局部作用域
-
因為函數的語句塊中沒有類似于?x =? 的語句,所以 y = x + 1?中的?x?會從上一級找,從而不報錯x = 5def fn():????y = x + 1????print(x)fn()因為函數會先掃描語句塊,且函數的語句塊中有?x =?的語句,所以會先調用本地的變量,但是本地并沒有賦值,所以就會報錯,記住一句話:賦值即定義x = 5def fn():????y = x + 1????x += 1????print(x)fn()
-
使用?global?關鍵字的變量,將?fn?內的?x?聲明為使用外部的全局作用域中定義的?x,且全局作用域中必須有?x?的定義x = 5def fn():????global x????x += 1????print(x)fn()
-
global?總結? ? ?x += 1?這種是特殊形式產生的錯誤原因是:先引用后賦值,而?Python?動態語言是賦值才算定義,才能被引用,解決辦法是在這條語句前增加?x = 0?之類的賦值語句,或者使用?global?告訴內部作用域,去全局作用域查找變量定義? ? ?內部作用域使用?x = 5?之類的賦值語句會重新定義局部作用域使用的變量?x,但是,一旦這個作用域中使用?global?聲明?x?為全局的,那么?x = 5?相當于在為全局作用域的變量?x?賦值
-
global?使用原則? ? ? 外部作用域變量會在內部作用域可見,但也不要在這個內部的局部作用域中直接使用,因為函數的目的就是為了封裝,盡量與外界隔離? ? ? 如果函數需要使用外部全局變量,請使用函數的形參傳參解決? ? ? 一句話:不用?global,學習它就是為了深入理解變量作用域
-
使用了?nonlocal?關鍵字,將變量標記為不在本地作用域中定義,而在上級的某一級局部作用域中定義,但不能是全局作用域中定義,這樣就形成閉包def counter():????cc = 0????def inc():????????nonlocal cc????????cc += 1????????return cc????return incfoo = counter()foo()
-
默認值的作用域def foo(xyz=[]):????xyz.append(1)????print(xyz)foo()? ?–> [1]foo()? ?–> [1,1]因為函數也是對象,Python?把函數的默認值放在了屬性中,這個屬性就伴隨這個函數對象的整個生命周期函數地址并沒有變,就是說函數這個對象的屬性沒有變,調用它,它的屬性? __defaults__?中所使用元祖保存默認值為了避免出現這種情況:? ? ? 使用影子拷貝創建一個新的對象def foo(xyz=[]):????xyz = xyz[:]????xyz.append(1)????print(xyz)foo()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?–>[1]print(foo.__defaults__)? ? ? ???–>([],)foo()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???–>[1]print(foo.__defaults__)? ? ? ? ?–>([],)foo([10])? ? ? ? ? ? ? ? ? ? ? ? ? ? ???–>[10,1]print(foo.__defaults__)? ? ? ? ? –>([],)? ? ? 通過值得判斷就可以靈活的選擇創建或者修改傳入對象def foo(xyz=None,u=’abc’,z=123):????if xyz is None:????????xyz = []????xyz.append(1)????print(xyz)foo()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?–>[1]print(foo.__defaults__)? ? ? ???–>(None,’abc’,123)foo()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???–>[1]print(foo.__defaults__)? ? ? ? ?–>(None,’abc’,123)foo([10])? ? ? ? ? ? ? ? ? ? ? ? ? ? ???–>[10,1]print(foo.__defaults__)? ? ? ? ? –>(None,’abc’,123)
-
屬性?__defaults__?中使用元祖保存所有位置參數默認值? ? ? ?屬性?__kwdefaults__?中使用字典保存所有 keyword-only?參數的默認值def foo(w,u=’abc’,*,z=123,zz=[456]):????u = ‘xyz’????z = 789????zz.append(1)????print(w,u,z,zz)print(foo.__defaults__)foo(‘magedu’)print(foo.__kwdefaults__)
-
一個變量的查找順序是?LEGB:Local(本地作用域)–> Enclosing(嵌套構成的閉包)–>Global(全局作用域) –>Build-in(內置模塊的命名空間)
-
全局函數銷毀? ? ? ? ? ? ?重新定義同名函數? ? ? ? ? ? ?del?語句刪除函數對象? ? ? ? ? ? ?程序結束時? ? ? 局部函數銷毀? ? ? ? ? ? ?重新在上級作用域定義同名函數? ? ? ? ? ? ?del?語句刪除函數對象? ? ? ? ? ? ?上級作用域銷毀時
本文來自投稿,不代表Linux運維部落立場,如若轉載,請注明出處:http://www.www58058.com/95946