python入门之函数调用第二关_猪行天下之Python基础——5.1 函数(上)
內容簡述:
1、函數定義
2、形參與實參
3、關鍵字參數與默認參數
4、可變參數
5、全局變量與局部變量
6、內部函數
7、閉包
8、lambda表達式
9、遞歸
1、函數定義
我們可以將一些實現特定功能,重復使用到的「代碼片段」抽取出來,封裝成一個函數。比如求兩個數和的函數:
def?plus(a,?b):
"""
計算兩個數的和
:param?a:?第一個參數
:param?b:?第二個參數
:return:?兩個參數的和
"""
return?a?+?b
if?__name__?==?'__main__':
print("1?+?2?=?%d"?%?plus(1,?2))
復制代碼
運行結果如下:
1?+?2?=?3
復制代碼
從上面的求和函數可以初窺函數定義的一些端倪,接著具體說下規則:
函數定義格式:def 函數名(傳入參數)
使用 `return` 返回值,不寫的話默認返回 None 值。
Python函數的 返回值可以有多個 ,本質上利用的元組。
Python傳遞的 參數有多個 的話,可以用逗號隔開。
一個建議:函數定義時,可在函數的第一行語句中選擇性地使用文檔字符串編寫函數說明,除了方便閱讀,使用help(函數名)也可以拿到這個函數的說明信息。
2、形參與實參
定義函數時,函數名后傳入的參數叫「形參」,調用函數時,函數名后傳入的參數叫「實參」。這里還涉及到一個「傳值與傳址」的問題,傳值就是傳入一個參數的值,而傳址則是傳入一個參數的內存地址。兩者的區別是:如果函數是傳值類型的,在函數里修改了參數的值,外部的變量(實參)是不會改變的,比如下面這樣一段代碼:
def?f(a):
a?=?1
b?=?0
f(b)
print(b)
復制代碼
運行結果如下:
0
復制代碼
盡管我們修改了傳入參數的值,但是實參卻依舊是0,沒有改變,這就是傳參,如果傳遞的是內存地址,修改的了話實參也會受影響。但是Python和其他編程語言有點不同(比如C語言里可以用&參數名傳地址)。
Python不允許開發者選擇采用傳值還是傳址,而是采用「傳對象引用」的方式,如果傳入的參數是一個不可變對象(數字,字符串和元組)的引用,就不能修改原始對象的值;如果傳入的參數是一個可變對象(列表,字典)的引用,就能直接修改原始對象的值。
比如下面這樣一串代碼:
def?f(a):
b[0]?=?1
b?=?[0]
f(b)
print(b)
復制代碼
運行結果如下:
[1]
復制代碼
3、關鍵字參數與默認參數
「關鍵字參數」:當函數需要傳入的參數有多個的時候,怕參數混淆傳錯,可以在傳入的時候指定形參的參數名,比如:plus(a = 1, b = 2)。
「默認參數」:在 定義形參的時候賦予初始值,調用的時候就可以不帶參數去調用函數,比如:
def plus(a=1, b = 2),調用的時候直接plus()或者只傳入一個參數plus(3)都是可以的,還可以配合關鍵字參數指定傳入的是哪個參數。另外,默認參數也稱作「缺省參數」。
4、可變參數
有時傳入函數中的 參數數目 可能是 不固定 的,比如,要你計算一堆數字的和,而具體有多少
個數字不知道,這個時候就可以使用可變參數了。只需要在函數定義時在參數前加上* 星號,
就代表這個參數是可變參數(其實是只是把數據打包成了一個元組)。
另外,如果除了可變參數外還有其他的參數,那么寫在可變參數后的參數要用關鍵字參數指定,
否則會加入可變參數的范疇。還有一點要注意,如果傳入的參數是列表或者元組,會被再次
打包成元組,如果想解包的話,需要在實參前加*,代碼示例如下:
def?plus(*a):
result?=?0
for?b?in?a:
print(b,?end='\t')
if?__name__?==?'__main__':
a?=?[1,?2,?3,?4,?5]
plus(a)
print()
plus(*a)
復制代碼
運行結果如下:
[1,?2,?3,?4,?5]
1???2???3???4???5
復制代碼
另外,如果想把參數打包成字典的方式,可在函數形參前使用兩個**標識。
5、全局變量與局部變量
全局變量:定義在最外部,可在函數內部進行訪問,但不能直接修改。
局部變量:定義在函數內部,在函數外部無法訪問的參數和變量。
局部變量無法在外部訪問的原因:
Python在運行函數時,會利用棧(Stack)來存儲數據,執行完函數后,所有數據會被自動刪除。
函數中無法修改全局變量的原因:
試圖在函數里修改全局變量的值時,Python會自動在函數內部新建一個名字一樣的局部變量代替。如果硬是要修改,可以在函數內部使用global關鍵字修飾全局變量,但是不建議這樣做,會使得程序維護成本的提高。
6、內部函數
所謂的內部函數其實就是「函數嵌套」,在一個函數中嵌套另一個函數,要注意:
內部函數的作用域,只在內部函數的「直接外部函數內」,外部是無法調用的沒,外部調用內部函數會直接報:函數找不到的錯誤!
內部函數無法直接修改外部函數中的變量,否則會報UnboundLocalError錯誤!如果想在內部函數中直接修改,可以把直接外部函數中的變量通過容器類型來存放,或者使用Python提供的 nonlocal關鍵字 修飾。代碼示例如下:
def?fun_x():
x?=?[10]
y?=?10
def?fun_y():
x[0]?+=?x[0]
nonlocal?y
y?*=?y
return?x[0]?*?y
return?fun_y()
if?__name__?==?'__main__':
print(fun_x())
復制代碼
運行結果如下:
2000
復制代碼
7、閉包
在函數內嵌套了另一個函數,如果「內部函數引用了外部函數的變量」,則可能產生閉包。
Python中形成閉包的三個條件:
函數嵌套
內部函數引用外部變量
外部函數返回內部函數
一個函數閉包的代碼示例如下:
def?outer(a):
b?=?1
def?inner():
print(a?+?b)
return?inner
if?__name__?==?'__main__':
test_1?=?outer(2)
test_1()
復制代碼
運行結果如下:
2
復制代碼
在上面的代碼中,直接把內部函數當做返回值返回了,b是一個局部變量,按理來說,生命周期在調用完outer()函數后就完結了。但是載上面的代碼中,調用test_1時,b變量的值卻正常輸出了,函數閉包使得函數的「局部變量信息」得以保存。
Python中通過__closure__屬性保存閉包中的局部變量,把上面test_1函數里的東東
打印出來,代碼如下:
print(test_1.__closure__)
print(test_1.__closure__[0].cell_contents)
print(test_1.__closure__[1].cell_contents)
復制代碼
運行結果如下:
(,?)
2
1
復制代碼
8、lambda表達式
在Python中可以使用lambda關鍵字來創建匿名函數,直接返回一個函數對象,而不用去糾結給函數起什么名字,省去了定義函數的步驟,從而簡化代碼,一個對比大小簡單的lambda表達式代碼示例如下:
big?=?lambda?x,?y:?x?>?y
print("第一個參數比第二個參數大:%s"?%?big(1,?2))
復制代碼
運行結果如下:
第一個參數比第二個參數大:False
復制代碼
9、遞歸
所謂的遞歸就是「函數調用自身」,最簡單的遞歸求和代碼示例如下:
def?sum(n):
if?n?==?1:
return?1
else:
return?n?+?sum(n?-?1)
print("1到100的求和結果是:?%d"?%?sum(100))
復制代碼
運行結果如下:
1到100的求和結果是:?5050
復制代碼
另外要注意兩點:
遞歸要有結束條件,以避免遞歸的無休止調用!
遞歸可以簡化程序,但不一定能提高程序的執行效率!
如果本文對你有所幫助,歡迎
留言,點贊,轉發
素質三連,謝謝😘~
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的python入门之函数调用第二关_猪行天下之Python基础——5.1 函数(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql建表的auto_increme
- 下一篇: 关于MySQL数据库游标的笔试题_关于B