函式
函式是組織好的,可重複使用的,用來實現單一,或相關聯功能的程式碼段。
Python 提供了許多內建函式,比如 print()
。但你也可以自己建立函式,這被叫做使用者自定義函式。
定義一個函式
定義一個函式,以下是簡單的規則:
- 函式程式碼塊以
def
關鍵詞開頭,後接函式識別符號名稱和圓括號()
- 任何傳入引數和自變數必須放在圓括號中間,圓括號之間可以用於定義引數
- 函式的第一行語句可以選擇性地使用文件字串:用於存放函式說明
- 函式內容以冒號
:
起始,並且縮排 return [表示式]
結束函式,選擇性地返回一個值給呼叫方,不帶表示式的return
相當於返回None
語法
Python 定義函式使用 def
關鍵字,一般格式如下:
def 函式名(引數列表):
函式體
預設情況下,引數值和引數名稱是按函式宣告中定義的順序匹配起來的。
例項
使用函式來輸出"Hello World!":
#!/usr/bin/python3
def hello():
print("Hello World!")
hello()
hello()
函式中帶上引數變數:
#!/usr/bin/python3
def max(a, b):
if a > b:
return a
else:
return b
a = 4
b = 5
print(max(a, b))
函式呼叫
定義一個函式:給了函式一個名稱,指定了函式里包含的引數,和程式碼塊結構。
這個函式的基本結構完成以後,你可以透過另一個函式呼叫執行,也可以直接從 Python 命令提示符執行。
#!/usr/bin/python3
# 定義函式
def printme(str):
# 列印任何傳入的字串
print(str)
return
# 呼叫函式
printme("我要呼叫使用者自定義函式!")
printme("再次呼叫同一函式")
引數傳遞
在 python 中,型別屬於物件,物件有不同型別的區分,變數是沒有型別的:
a=[1,2,3]
a="Runoob"
變數 a
是沒有型別,它僅僅是一個物件的引用(一個指標),可以是指向 List
型別物件,也可以是指向 String
型別物件
可更改(mutable)與不可更改(immutable)物件
在 python 中,strings, tuples 和 numbers 是不可更改的物件,而 list, dict 等則是可以修改的物件。
- 不可變型別:變數賦值 a=5 後再賦值 a=10,這裡實際是新生成一個 int 值物件 10,再讓 a 指向它,而 5 被丟棄,不是改變 a 的值,相當於新生成了 a
- 可變型別:變數賦值 la=[1,2,3,4] 後再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了
python 函式的引數傳遞:
- 不可變型別:類似 C++ 的值傳遞,如整數、字串、元組。如
fun(a)
,傳遞的只是 a 的值,沒有影響 a 物件本身。如果在fun(a)
內部修改 a 的值,則是新生成一個 a 的物件 - 可變型別:類似 C++ 的引用傳遞,如 列表,字典。如
fun(la)
,則是將 la 真正的傳過去,修改後fun
外部的 la 也會受影響
python 中一切都是物件,嚴格意義我們不能說值傳遞還是引用傳遞,我們應該說傳不可變物件和傳可變物件。
傳不可變物件例項
透過 id()
函式來檢視記憶體地址變化:
def change(a):
print(1, id(a)) # 指向的是同一個物件
a = 10
print(2, id(a)) # 一個新物件
a = 1
print(0, id(a))
change(a)
print(3, id(a))
輸出結果為:
0 2682404864240
1 2682404864240
2 2682404864528
3 2682404864240
傳可變物件例項
#!/usr/bin/python3
# 可寫函式說明
def changeme(mylist):
"修改傳入的列表"
mylist.append([1, 2, 3, 4])
print("函式內取值: ", mylist)
return
# 呼叫changeme函式
mylist = [10, 20, 30]
changeme(mylist)
print("函式外取值: ", mylist)
輸出結果如下:
函式內取值: [10, 20, 30, [1, 2, 3, 4]]
函式外取值: [10, 20, 30, [1, 2, 3, 4]]
引數
以下是呼叫函式時可使用的正式引數型別:
- 必需引數
- 關鍵字引數
- 預設引數
- 不定長引數
必需引數
必需引數須以正確的順序傳入函式。呼叫時的數量必須和宣告時的一樣。
關鍵字引數
關鍵字引數和函式呼叫關係緊密,函式呼叫使用關鍵字引數來確定傳入的引數值。
使用關鍵字引數允許函式呼叫時引數的順序與宣告時不一致,因為 Python 直譯器能夠用引數名匹配引數值。
函式引數的使用不需要使用指定順序:
#!/usr/bin/python3
# 可寫函式說明
def printinfo(name, age):
"列印任何傳入的字串"
print("名字: ", name)
print("年齡: ", age)
return
# 呼叫printinfo函式
printinfo(age=50, name="runoob")
預設引數
呼叫函式時,如果沒有傳遞引數,則會使用預設引數。
#!/usr/bin/python3
# 可寫函式說明
def printinfo(name, age=35):
"列印任何傳入的字串"
print("名字: ", name)
print("年齡: ", age)
return
# 呼叫printinfo函式
printinfo(age=50, name="runoob")
print("------------------------")
printinfo(name="runoob")
輸出結果:
名字: runoob
年齡: 50
------------------------
名字: runoob
年齡: 35
不定長引數
基本語法如下:
def functionname([formal_args,] *var_args_tuple ):
"函式_文件字串"
function_suite
return [expression]
加了星號 *
的引數會以元組(tuple) 的形式匯入,存放所有未命名的變數引數。
#!/usr/bin/python3
# 可寫函式說明
def printinfo(arg1, *vartuple):
"列印任何傳入的引數"
print("輸出: ")
print(arg1)
print(vartuple)
# 呼叫 printinfo 函式
printinfo(70, 60, 50)
輸出結果:
輸出:
70
(60, 50)
如果在函式呼叫時沒有指定引數,它就是一個空元組。
我們也可以不向函式傳遞未命名的變數。
#!/usr/bin/python3
# 可寫函式說明
def printinfo(arg1, *vartuple):
"列印任何傳入的引數"
print("輸出: ")
print(arg1)
print(vartuple)
for var in vartuple:
print(var)
return
# 呼叫printinfo 函式
printinfo(10)
輸出結果:
輸出:
10
()
還有一種就是引數帶兩個星號 **
基本語法如下:
def functionname([formal_args,] **var_args_dict ):
"函式_文件字串"
function_suite
return [expression]
加了兩個星號 **
的引數會以字典的形式匯入。
#!/usr/bin/python3
# 可寫函式說明
def printinfo(arg1, **vardict):
"列印任何傳入的引數"
print("輸出: ")
print(arg1)
print(vardict)
# 呼叫printinfo 函式
printinfo(1, a=2, b=3)
輸出結果:
輸出:
1
{'a': 2, 'b': 3}
宣告函式時,引數中星號 *
可以單獨出現,例如:
def f(a,b,*,c):
return a+b+c
如果單獨出現星號 *
後的引數必須用關鍵字傳入。
def f(a, b, *, c):
return a + b + c
# f(1, 2, 3) # TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3) # 正常
匿名函式
Python 使用 lambda
來建立匿名函式。
所謂匿名,意即不再使用 def
語句這樣標準的形式定義一個函式。
lambda
只是一個表示式,函式體比def
簡單很多lambda
的主體是一個表示式,而不是一個程式碼塊。僅僅能在 lambda 表示式中封裝有限的邏輯進去- lambda 函式擁有自己的名稱空間,且不能訪問自己引數列表之外或全域性名稱空間裡的引數
- 雖然 lambda 函式看起來只能寫一行,卻不等同於 C 或 C++ 的行內函數,後者的目的是呼叫小函式時不佔用棧記憶體從而增加執行效率
語法
lambda 函式的語法只包含一個語句,如下:
lambda [arg1 [,arg2,.....argn]]:expression
設定引數 a 加上 10 :
x = lambda a: a + 10
print(x(5)) # 15
以下例項匿名函式設定兩個引數:
#!/usr/bin/python3
# 可寫函式說明
sum = lambda arg1, arg2: arg1 + arg2
# 呼叫sum函式
print("相加後的值為 : ", sum(10, 20)) # 30
print("相加後的值為 : ", sum(20, 20)) # 40
我們可以將匿名函式封裝在一個函式內,這樣可以使用同樣的程式碼來建立多個匿名函式。
以下例項將匿名函式封裝在 myfunc
函式中,透過傳入不同的引數來建立不同的匿名函式:
def myfunc(n):
return lambda a: a * n
mydoubler = myfunc(2)
mytripler = myfunc(3)
print(mydoubler(11)) # 22
print(mytripler(11)) # 33
return 語句
return [表示式]
語句用於退出函式,選擇性地向呼叫方返回一個表示式。不帶引數值的 return
語句返回 None
強制位置引數
Python3.8 新增了一個函式形參語法 / 用來指明函式形參必須使用指定位置引數,不能使用關鍵字引數的形式。
在以下的例子中,形參 a 和 b 必須使用指定位置引數,c 或 d 可以是位置形參或關鍵字形參,而 e 和 f 要求為關鍵字形參:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
以下使用方法是正確的:
f(10, 20, 30, d=40, e=50, f=60)
以下使用方法會發生錯誤:
f(10, b=20, c=30, d=40, e=50, f=60) # b 不能使用關鍵字引數的形式
f(10, 20, 30, 40, 50, f=60) # e 必須使用關鍵字引數的形式