函數(shù)是組織好的复濒,可重復(fù)使用的,用來實(shí)現(xiàn)單一乒省,或相關(guān)聯(lián)功能的代碼段巧颈。
函數(shù)能提高應(yīng)用的模塊性,和代碼的重復(fù)利用率袖扛。
定義一個(gè)函數(shù)
- 函數(shù)代碼塊以 def 關(guān)鍵詞開頭砸泛,后接函數(shù)標(biāo)識(shí)符名稱和圓括號(hào) ()。
- 任何傳入?yún)?shù)和自變量必須放在圓括號(hào)中間蛆封,圓括號(hào)之間可以用于定義參數(shù)唇礁。
- 函數(shù)的第一行語句可以選擇性地使用文檔字符串—用于存放函數(shù)說明。
- 函數(shù)內(nèi)容以冒號(hào)起始惨篱,并且縮進(jìn)盏筐。
- return [表達(dá)式] 結(jié)束函數(shù),選擇性地返回一個(gè)值給調(diào)用方砸讳。不帶表達(dá)式的return相當(dāng)于返回 None琢融。
語法
Python 定義函數(shù)使用 def 關(guān)鍵字界牡,一般格式如下:
def 函數(shù)名(參數(shù)列表):
函數(shù)體
默認(rèn)情況下,參數(shù)值和參數(shù)名稱是按函數(shù)聲明中定義的順序匹配起來的漾抬。
實(shí)例
>>> def hello() :
print("Hello World!")
>>> hello()
Hello World!
>>>
#!/usr/bin/python3
# 計(jì)算面積函數(shù)
def area(width, height):
return width * height
def print_welcome(name):
print("Welcome", name)
print_welcome("Runoob")
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))
函數(shù)調(diào)用
定義一個(gè)函數(shù):給了函數(shù)一個(gè)名稱宿亡,指定了函數(shù)里包含的參數(shù),和代碼塊結(jié)構(gòu)纳令。
這個(gè)函數(shù)的基本結(jié)構(gòu)完成以后挽荠,你可以通過另一個(gè)函數(shù)調(diào)用執(zhí)行,也可以直接從 Python 命令提示符執(zhí)行平绩。
#!/usr/bin/python3
# 定義函數(shù)
def printme( str ):
"打印任何傳入的字符串"
print (str)
return
# 調(diào)用函數(shù)
printme("我要調(diào)用用戶自定義函數(shù)!")
printme("再次調(diào)用同一函數(shù)")
參數(shù)傳遞
在 python 中圈匆,類型屬于對(duì)象,變量是沒有類型的:
//變量 a 是沒有類型馒过,她僅僅是一個(gè)對(duì)象的引用(一個(gè)指針)
a=[1,2,3] // List 類型
a="Runoob" // String 類型
可更改(mutable)與不可更改(immutable)對(duì)象
在 python 中臭脓,strings, tuples, 和 numbers 是不可更改的對(duì)象,而 list,dict 等則是可以修改的對(duì)象腹忽。
- 不可變類型:變量賦值 a=5 后再賦值 a=10来累,這里實(shí)際是新生成一個(gè) int 值對(duì)象 10,再讓 a 指向它窘奏,而 5 被丟棄嘹锁,不是改變a的值,相當(dāng)于新生成了a着裹。
- 可變類型:變量賦值 la=[1,2,3,4] 后再賦值 la[2]=5 則是將 list la 的第三個(gè)元素值更改领猾,本身la沒有動(dòng),只是其內(nèi)部的一部分值被修改了骇扇。
python 函數(shù)的參數(shù)傳遞:
- 不可變類型:類似 c++ 的值傳遞摔竿,如 整數(shù)、字符串少孝、元組继低。如fun(a),傳遞的只是a的值稍走,沒有影響a對(duì)象本身袁翁。比如在 fun(a)內(nèi)部修改 a 的值,只是修改另一個(gè)復(fù)制的對(duì)象婿脸,不會(huì)影響 a 本身粱胜。
- 可變類型:類似 c++ 的引用傳遞,如 列表狐树,字典焙压。如 fun(la),則是將 la 真正的傳過去,修改后fun外部的la也會(huì)受影響
//python 傳不可變對(duì)象實(shí)例
#!/usr/bin/python3
def ChangeInt( a ):
a = 10
b = 2
ChangeInt(b)
print( b ) # 結(jié)果是 2
//實(shí)例中有 int 對(duì)象 2冗恨,指向它的變量是 b答憔,在傳遞給 ChangeInt 函數(shù)時(shí),按傳值的方式復(fù)制了變量 b掀抹,a 和 b 都指向了同一個(gè) Int 對(duì)象,在 a=10 時(shí)心俗,則新生成一個(gè) int 值對(duì)象 10傲武,并讓 a 指向它。
//傳可變對(duì)象實(shí)例
# 可寫函數(shù)說明
def changeme( mylist ):
"修改傳入的列表"
mylist.append([1,2,3,4])
print ("函數(shù)內(nèi)取值: ", mylist)
return
# 調(diào)用changeme函數(shù)
mylist = [10,20,30]
changeme( mylist )
print ("函數(shù)外取值: ", mylist)
函數(shù)內(nèi)取值: [10, 20, 30, [1, 2, 3, 4]]
函數(shù)外取值: [10, 20, 30, [1, 2, 3, 4]]
參數(shù)
以下是調(diào)用函數(shù)時(shí)可使用的正式參數(shù)類型:
1城榛、必需參數(shù)
2揪利、關(guān)鍵字參數(shù)
3、默認(rèn)參數(shù)
4狠持、不定長參數(shù)
必需參數(shù)
必需參數(shù)須以正確的順序傳入函數(shù)疟位。調(diào)用時(shí)的數(shù)量必須和聲明時(shí)的一樣。
#!/usr/bin/python3
#可寫函數(shù)說明
def printme( str ):
"打印任何傳入的字符串"
print (str)
return
#調(diào)用printme函數(shù)
printme()
//以上實(shí)例輸出結(jié)果:
Traceback (most recent call last):
File "test.py", line 10, in <module>
printme()
TypeError: printme() missing 1 required positional argument: 'str'
關(guān)鍵字參數(shù)
關(guān)鍵字參數(shù)和函數(shù)調(diào)用關(guān)系緊密喘垂,函數(shù)調(diào)用使用關(guān)鍵字參數(shù)來確定傳入的參數(shù)值甜刻。
使用關(guān)鍵字參數(shù)允許函數(shù)調(diào)用時(shí)參數(shù)的順序與聲明時(shí)不一致,因?yàn)?Python 解釋器能夠用參數(shù)名匹配參數(shù)值正勒。
#!/usr/bin/python3
#可寫函數(shù)說明
def printinfo( name, age ):
"打印任何傳入的字符串"
print ("名字: ", name)
print ("年齡: ", age)
return
#調(diào)用printinfo函數(shù)
printinfo( age=50, name="runoob" )
默認(rèn)參數(shù)
調(diào)用函數(shù)時(shí)得院,如果沒有傳遞參數(shù),則會(huì)使用默認(rèn)參數(shù)章贞。以下實(shí)例中如果沒有傳入 age 參數(shù)祥绞,則使用默認(rèn)值:
#!/usr/bin/python3
#可寫函數(shù)說明
def printinfo( name, age = 35 ):
"打印任何傳入的字符串"
print ("名字: ", name)
print ("年齡: ", age)
return
#調(diào)用printinfo函數(shù)
printinfo( age=50, name="runoob" )
print ("------------------------")
printinfo( name="runoob" )
不定長參數(shù)
你可能需要一個(gè)函數(shù)能處理比當(dāng)初聲明時(shí)更多的參數(shù)。這些參數(shù)叫做不定長參數(shù)鸭限,和上述2種參數(shù)不同蜕径,聲明時(shí)不會(huì)命名“芫基本語法如下:
//加了星號(hào)(*)的變量名會(huì)存放所有未命名的變量參數(shù)兜喻。
//如果在函數(shù)調(diào)用時(shí)沒有指定參數(shù),它就是一個(gè)空元組
def functionname([formal_args,] *var_args_tuple ):
"函數(shù)_文檔字符串"
function_suite
return [expression]
#!/usr/bin/python3
# 可寫函數(shù)說明
def printinfo( arg1, *vartuple ):
"打印任何傳入的參數(shù)"
print ("輸出: ")
print (arg1)
for var in vartuple:
print (var)
return
# 調(diào)用printinfo 函數(shù)
printinfo( 10 )
printinfo( 70, 60, 50 )
輸出:
10
輸出:
70
60
50
匿名函數(shù)
python 使用 lambda 來創(chuàng)建匿名函數(shù)喧枷。
所謂匿名虹统,意即不再使用 def 語句這樣標(biāo)準(zhǔn)的形式定義一個(gè)函數(shù)。
- lambda 只是一個(gè)表達(dá)式隧甚,函數(shù)體比 def 簡單很多车荔。
- lambda的主體是一個(gè)表達(dá)式,而不是一個(gè)代碼塊戚扳。僅僅能在lambda表達(dá)式中封裝有限的邏輯進(jìn)去忧便。
- lambda 函數(shù)擁有自己的命名空間,且不能訪問自己參數(shù)列表之外或全局命名空間里的參數(shù)。
- 雖然lambda函數(shù)看起來只能寫一行珠增,卻不等同于C或C++的內(nèi)聯(lián)函數(shù)超歌,后者的目的是調(diào)用小函數(shù)時(shí)不占用棧內(nèi)存從而增加運(yùn)行效率。
語法
lambda 函數(shù)的語法只包含一個(gè)語句蒂教,如下:
lambda [arg1 [,arg2,.....argn]]:expression
#!/usr/bin/python3
# 可寫函數(shù)說明
sum = lambda arg1, arg2: arg1 + arg2
# 調(diào)用sum函數(shù)
print ("相加后的值為 : ", sum( 10, 20 ))
print ("相加后的值為 : ", sum( 20, 20 ))
return語句
return [表達(dá)式] 語句用于退出函數(shù)巍举,選擇性地向調(diào)用方返回一個(gè)表達(dá)式。不帶參數(shù)值的return語句返回None凝垛。之前的例子都沒有示范如何返回?cái)?shù)值懊悯,以下實(shí)例演示了 return 語句的用法:
#!/usr/bin/python3
# 可寫函數(shù)說明
def sum( arg1, arg2 ):
# 返回2個(gè)參數(shù)的和."
total = arg1 + arg2
print ("函數(shù)內(nèi) : ", total)
return total
# 調(diào)用sum函數(shù)
total = sum( 10, 20 )
print ("函數(shù)外 : ", total)
變量作用域
Python 中,程序的變量并不是在哪個(gè)位置都可以訪問的梦皮,訪問權(quán)限決定于這個(gè)變量是在哪里賦值的炭分。
變量的作用域決定了在哪一部分程序可以訪問哪個(gè)特定的變量名稱。Python的作用域一共有4種剑肯,分別是:
- L (Local) 局部作用域
- E (Enclosing) 閉包函數(shù)外的函數(shù)中
- G (Global) 全局作用域
- B (Built-in) 內(nèi)建作用域
以 L –> E –> G –>B 的規(guī)則查找捧毛,即:在局部找不到,便會(huì)去局部外的局部找(例如閉包)让网,再找不到就會(huì)去全局找呀忧,再者去內(nèi)建中找。
x = int(2.9) # 內(nèi)建作用域
g_count = 0 # 全局作用域
def outer():
o_count = 1 # 閉包函數(shù)外的函數(shù)中
def inner():
i_count = 2 # 局部作用域
Python 中只有模塊(module)寂祥,類(class)以及函數(shù)(def荐虐、lambda)才會(huì)引入新的作用域,
其它的代碼塊(如 if/elif/else/丸凭、try/except福扬、for/while等)是不會(huì)引入新的作用域的,也就是說這些語句內(nèi)定義的變量惜犀,外部也可以訪問铛碑,如下代碼:
//msg 變量定義在 if 語句塊中,但外部還是可以訪問的虽界。
>>> if True:
... msg = 'I am from Runoob'
...
>>> msg
'I am from Runoob'
>>>
//如果將 msg 定義在函數(shù)中汽烦,則它就是局部變量,外部不能訪問:
>>> def test():
... msg_inner = 'I am from Runoob'
...
>>> msg_inner
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'msg_inner' is not defined
>>>
全局變量和局部變量
定義在函數(shù)內(nèi)部的變量擁有一個(gè)局部作用域莉御,定義在函數(shù)外的擁有全局作用域撇吞。
調(diào)用函數(shù)時(shí),所有在函數(shù)內(nèi)聲明的變量名稱都將被加入到作用域中礁叔。
#!/usr/bin/python3
total = 0 # 這是一個(gè)全局變量
# 可寫函數(shù)說明
def sum( arg1, arg2 ):
#返回2個(gè)參數(shù)的和."
total = arg1 + arg2 # total在這里是局部變量.
print ("函數(shù)內(nèi)是局部變量 : ", total)
return total
#調(diào)用sum函數(shù)
sum( 10, 20 )
print ("函數(shù)外是全局變量 : ", total)
函數(shù)內(nèi)是局部變量 : 30
函數(shù)外是全局變量 : 0
global 和 nonlocal關(guān)鍵字
當(dāng)內(nèi)部作用域想修改外部作用域的變量時(shí)牍颈,就要用到global和nonlocal關(guān)鍵字了。
#!/usr/bin/python3
num = 1
def fun1():
global num # 需要使用 global 關(guān)鍵字聲明
print(num)
num = 123
print(num)
fun1()
1
123
如果要修改嵌套作用域(enclosing 作用域琅关,外層非全局作用域)中的變量則需要 nonlocal 關(guān)鍵字了煮岁,如下實(shí)例:
#!/usr/bin/python3
def outer():
num = 10
def inner():
nonlocal num # nonlocal關(guān)鍵字聲明
num = 100
print(num)
inner()
print(num)
outer()
100
100
//錯(cuò)誤信息為局部作用域引用錯(cuò)誤,因?yàn)?test 函數(shù)中的 a 使用的是局部,未定義画机,無法修改冶伞。
#!/usr/bin/python3
a = 10
def test():
a = a + 1
print(a)
test()
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 5, in test
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment