函數
數學函數
Python函數
若干語句塊、函數名稱、參數列表構成,組織代碼的最小單元
完成一定的功能
作用
結構化編程對代碼的最基本的封裝,一般按照功能組織一段代碼
復用,減少冗余代碼
簡潔美觀,可讀易懂
函數分類
內建函數,max()、reversed()
庫函數,math.ceil()
函數定義、調用
def語句定義函數
def 函數名(參數列表):
函數體
[return 返回值]
函數名為標識符,要求按照標識符的命名規則
語句塊必須縮進,4個空格
若沒有return語句,默認返回None值
定義中的參數列表成為形式參數,形參
調用
函數定義,只是聲明了一個函數,需要調用才能被執行
調用方式:函數名(參數)
調用時給定的參數是實際參數,實參,是實實在在傳入的值
函數是可調用對象,callable()
函數參數
函數調用時傳入的參數要和定義的個數相匹配(可變參數例外)
位置參數
按照參數定義順序傳入實參
關鍵字參數
使用形參的名字來傳入實參,若使用了形參的名字,則傳參順序和定義順序可不同
傳參
要求位置參數必須在關鍵字參數之前傳入,位置參數是按位置對應的
參數默認值
定義函數時,在形參后面給定一個值
作用
在未傳入足夠的實參時,對沒有給定的參數賦值為默認值
參數非常多時,不需要用戶每次輸入所有參數,簡化函數調用
可變參數
位置參數的可變參數
一個形參可以匹配任意個參數
在形參前使用*表示該形參是可變參數,可以接收多個實參
收集多個實參為一個tuple
關鍵字參數的可變參數
形參前使用**表示可以接收多個關鍵字參數
收集的實參名稱和值組成一個字典
混合使用參數時,可變參數要放到參數列表的最后,普通參數需要放在參數列表的前面,位置可變參數需要放在關鍵字參數之前
?
?
相同參數不能重復賦值
keyword-only參數
在一個*參數后面或者一個位置可變參數后面,若出現的是普通參數,實際上不在是普通參數了,而是keyword-only參數
*args可以收集所有的位置參數,如果其后的普通參數不使用關鍵字參數的方式傳遞參數就得不到參數
不能使用**kwargs后面跟普通參數的方式傳遞參數,原因:即使后面的普通參數使用關鍵字的方式傳遞參數也會被**kwargs收集,導致普通參數無法獲取到參數
def fn(*,x,y):在*號之后,普通形參都變成了必須給出的keyword-only參數
參數規則
參數列表的一般順序:普通參數、缺省參數、可變位置參數、keyword-only參數(可帶缺省值)、可變關鍵字參數
def fn(x, y, z=3, *arg, m=4, n, **kwargs):
參數解構
在給函數提供實參的時候,可以在集合類型前使用*或**將集合類型 的結構解開,提取出所有元素作為函數的實參
非字典類型使用*解構成位置參數
字典類型使用**解構成關鍵字參數
提取出來的元素個數和參數要求的要一致,且要類型匹配
函數的返回值、作用域
返回值
使用return語句返回”返回值”
所有函數都有返回值,若沒有return語句則隱式調用return None
Return語句并不一定是函數的語句塊的最后一條語句
一個函數可以存在多個return語句,但是只有一條能夠被執行,如果return語句都沒有執行,隱式調用return None
若有必要,可顯式調用return None,簡寫return
如果函數執行了return語句,函數就會返回,當前被執行的return語句后面的其他語句將不會被執行
作用:結束函數調用,返回值
?
?
返回值只能有一個,不能同時返回多個值
return [1,2,3]指明返回一個列表,是一個列表對象
return 1,2,3 看似返回多個值,實則隱式被封裝成了一個元組
使用x,y,z = show()的方式可以方便的解構提取
函數嵌套
在一個函數中定義了另一個函數
函數有可見范圍,即作用域
內部函數不能被外部直接調用,會拋NameError異常
作用域
一個標識符的可見范圍,就是標識符的作用域,即變量的作用域
全局作用域
在整個程序運行環境都可見
局部作用域
在函數、類等內部可見
使用范圍不能超出其所在的局部作用域
外層變量在內層作用域可見
內層作用域中如果定義和外層作用域中同名的變量,相當于在當前作用域中重新定義了一個新的變量,但該變量并沒有覆蓋外層作用域中的同名變量
錯誤原因
x += 1等價于x = x + 1
相當于在foo內部定義了一個局部變量x,foo內部均使用該局部變量x
但是x還未完成賦值,就被用來做+1操作
全局變量global
使用global關鍵字的變量,將內部變量x聲明為使用外部的全局作用域中定義的x
若內部作用域中未定義x,則在全局作用域中必須有x的定義
若全局作用域中未定義x,則在內部作用域中可為x賦值,即在內部作用域為一個外部作用域的變量賦值,x的作用域為全局
使用規則
外部作用域變量在內部作用域可見,但不要在內部作用域中直接使用,因為函數的目的就是為了封裝,實現和外界的隔離
若函數需要使用外部全局變量,可使用函數的形參傳參
盡量不用global
閉包
自由變量:未在本地作用域中定義的變量,定義在內部函數外的外層函數中的作用域中的變量
閉包:在嵌套函數中,內層函數引用到了外層函數的自由變量
nonlocal關鍵字:將變量標記為不在本地作用域中定義,而在上級的某一級局部作用域中定義,而不能在全局作用域中定義
默認值的作用域
函數地址未改變,即函數對象沒有改變,它的屬性__defaults__中使用元組保存默認值
w的默認值為引用類型,引用類型的元素變動,元組并未變化
傳遞參數時未使用到默認值,默認值不會改變
屬性__defaults__中使用元組保存所有位置的默認值,w的默認值為簡單類型,不可變,即使return w也不會改變函數的默認值
?
?
屬性__kwdefaults__中使用字典保存所有keyword-only參數的默認值
默認值修改
方法1
使用影子拷貝創建一個新的對象,永遠不能改變傳入的參數
方法2
通過值的判斷靈活的選擇創建或修改傳入的對象
方式靈活,應用廣泛
使用None這個不可變的值作為默認參數,是一種慣用方法
變量名解析原則
順序:LEGB
Local:本地作用域、局部作用域的local命名空間,函數調用時創建,調用結束消亡
Enclosing:嵌套函數的外部函數的命名空間
Global:全局作用域,即一個模塊的命名空間,模塊被import時創建,解釋器退出時消亡
Build-in:內置函數的命名空間,從解釋器啟動時創建到解釋器退出時消亡
函數的銷毀
全局函數銷毀
重新定義同名函數
del語句刪除函數對象
程序結束時
局部函數銷毀
重新在上級作用域定義同名函數
del語句刪除函數對象
上級作用域銷毀時
遞歸函數
遞歸
函數直接或間接調用自身
需要有邊界條件、遞歸前進段、遞歸返回段
一定要有邊界條件
當邊界條件不滿足時,遞歸前進
當遞歸條件滿足時,遞歸返回
遞歸要求
一定要有退出條件,遞歸調用一定要執行到這個退出條件。沒有退出條件的遞歸調用,就是無限調用
遞歸調用的深度不易過深
python對遞歸調用的深度做了限制,已保護解釋器
超過遞歸深度限制,拋出超出最大深度異常
sys.getrecursionlimit()查看深度限制
遞歸的性能
循環稍復雜,但只要不是死循環,就可以多次迭代直至算出結果
遞歸有深度限制,如果遞歸復雜,函數反復壓棧,棧內存很快就溢出了
間接遞歸
通過別的函數調用了函數自身
構成循環遞歸調用時非常危險的,要用代碼的規范來避免這種遞歸調用的發生
總結
遞歸是一種很自然的表達,符合邏輯思維
遞歸相對運行效率低,每一次調用函數都要開辟棧幀
遞歸有深度限制,若遞歸藏瓷太深,函數反復壓棧,棧內存很快就溢出了
如果是有限次的遞歸,可以使用遞歸調用,或使用循環代替
絕大多數遞歸都可以通過循環實現
雖然遞歸代碼簡潔,但是能不用則不用為好
匿名函數
使用lambda表達式構建函數
格式
lambda 參數列表 :表達式
特點
使用lambda關鍵字來定義匿名函數
參數列表不需要小括號
使用冒號分割參數列表和表達式
不需要使用return,表達式的值即為匿名函數的返回值
Lambda表達式只能寫在一行上,被稱為單行函數
用途
在高階函數傳參時,使用lambda表達式,能簡化代碼
原創文章,作者:ZBD20,如若轉載,請注明出處:http://www.www58058.com/96272