Python 函式,參數,傳回值介紹,以及 Python 函式的定義和呼叫

閱讀 11:30·字數 3452·發佈 
Youtube 頻道
訂閱 133

先決條件

閱讀本節的先決條件是已經掌握函式,參數等概念,你可以檢視程式設計教學函式,參數,傳回值介紹一節來了解他們。

定義 Python 函式

通常情況下,Python 函式定義在模組中,並作為可被外部呼叫的目標,其基本的書寫格式如下。

def <funcname>(<parameterlist>)
    <docstring>
    <block>

funcname 部分

funcname為函式名稱,他需要符合 Python 的識別碼規格,不能使用 Python 關鍵字或保留關鍵字。

parameterlist 部分

parameterlist是函式的參數表,他定義了函式的所有參數,參數之間使用,進行分隔。

docstring 部分

docstring是函式的文件字串,包含了對函式的說明,這並非強製性的要求,一個函式可以沒有文件字串。

block 部分

block為函式的主體程式碼,他和docstring都需要使用某種空白字元進行縮排,以表示其歸屬於函式。

下面是一個簡單的 Python 函式hello,擁有一個名稱為name的參數。

functions.py
# 定義一個具有參數 name 的函式 hello
def hello(name):
	'''一個超級簡單的函式'''
	print(f'你好,{name}')

呼叫 Python 函式

在任何語言中,呼叫函式都是一件輕松的事情,Python 也是如此,以下是呼叫函式的基本格式。

<funcname>(<argumentlist>)

funcname 部分

funcname為需要呼叫的函式名稱。

argumentlist 部分

argumentlist是向函式傳遞的引數表。

在下面的程式碼中,我們呼叫了函式hello,並傳遞了引數'Kitty'

functions.py
# 呼叫函式 hello
hello('Kitty')
你好,Kitty

Python 程式碼縮排

Python 通過縮排來說明程式碼層級結構,縮排一般通過空格字元或定位字元實作。從行開頭開始計算,擁有相同數量空格字元或定位字元的程式碼被視為同一層次。

不要在 Python 中混合使用空格字元和定位字元進行縮排

雖然,在一個 Python 腳本檔案中,混合使用空格字元和定位字元進行縮排是被允許的,比如,使用兩個空格表示一個層次,使用三個定位字元表示另一個層次。但這並不是可取的行為,因為他可能會導致不必要的錯誤,或讓程式碼的可讀性下降。

Python 函式的參數

Python 函式的參數可以擁有預設值,在定義時使用=進行設定即可,預設值僅運算一次,因此參數的預設值會指向同一個物件。如果預設值是一個串列,那麽每次呼叫函式時,串列包含的元素可能會不同。

如何限製 Python 函式的參數為位置參數?

為 Python 函式增加特殊符號/,該符號之前的參數只能作為位置參數使用。

如何限製 Python 函式的參數為關鍵字參數?

為 Python 函式增加*標記的可變參數(可以僅保留*自身),該參數之後的參數只能作為關鍵字(命名)參數使用。在一個函式中,使用*標記的參數只能出現在符號/之後,否則位置參數將無法被確定。

下面的函式add,其參數xy擁有預設值,且只能作為位置參數使用,參數z只能作為關鍵字參數使用。當參數y使用其預設值時,串列中的元素會隨著呼叫次數的增多而增多。

functions.py
# 定義加法函式
def add(x=1, y=[], /, *, z):
	# 串列 y 新增數值 100
	y.append(100)
	print(y)

# 計算 x,y,z 含有的數值之和 num = 0 for i in y: num += i
return x + num + z
# z 只能作為關鍵字參數使用 print(add(z=1)) # x 作為位置參數被使用 print(add(1, z=3))
[100]
102
[100, 100]
204

Python 函式的可變參數

在 Python 函式的參數前新增***後,參數將成為可變參數。其中符號*標記的參數是一個元組,他包含了呼叫該函式時,所有未在參數表中的位置參數。符號**標記的參數是一個字典,他應該位於參數表的最後,包含了呼叫該函式時,所有未在參數表中的關鍵字參數,字典鍵值組的鍵是一個字串,表示了參數的名稱,鍵值組的值為參數對應的值。

如果在參數表中同時使用了***,則*後需要具有參數名稱。

如何為 Python 函式傳遞串列,元組,區域,字典中的值?

如果為函式參數準備的值,儲存在 Python 序列或對映物件中,那麽可通過拆解操作來簡化參數的傳遞。具體做法為,使用*拆解序列物件(包括串列,元組,區域range),使用**拆解對映物件(主要為字典)。

下面的函式mlp,其參數numsinfo均為可變參數。在呼叫時,我們為mlp傳遞了多個數值,以進行乘法計算。

functions.py
# 定義乘法函式
def mlp(*nums, **info):
	# 顯示關鍵字參數
	print(info)

# 計算 nums 中包含的位置參數 num = 1 for i in nums: num *= i
return num
# 傳遞了多個數值進行乘法計算 print(mlp(2, 3, 4, 5, tip='這裏是一個小小的提示'))
{'tip': '這裏是一個小小的提示'}
120

Python 函式的傳回值

使用return陳述式,可以為 Python 函式傳回指定的值,如果未使用returnreturn未給出傳回值,則函式預設傳回None

Python 函式的簽章

在預設情況下,Python 函式的簽章僅包含函式名稱,這意味著在同一個命名空間中,之後定義的函式會覆蓋之前定義的同名函式,無論其參數和傳回值如何。

在下面的程式碼中,第二次定義的函式wait將覆蓋第一次定義的wait,因此,最後的陳述式wait(3)呼叫的是第二個wait函式。

functions.py
# 該函式將被之後定義的 wait 覆蓋
def wait(seconds):
	print(f'等待 {seconds} 秒')

# 呼叫的是最先定義的 wait 函式 wait(3)
# 該函式將覆蓋之前定義的 wait def wait(hours, minutes=5): print(f'等待 {hours} 小時 {minutes} 分')
# 呼叫的是最後定義的 wait 函式 wait(3)
等待 3 秒
等待 3 小時 5 分

Python 函式的命名空間

是的,Python 函式擁有自己的命名空間,因此,你在函式內定義的變數,可以與函式外部的變數同名,他們會被區別對待。

Python 函式不能直接指派修改函式外部定義的變數

根據有效範圍的一般性原則,你可以在函式中存取函式外部定義的某個變數,但僅限於讀取,當你嘗試對外部變數寫入時,並不能達到預期效果,原因在於 Python 會將指派陳述式,認定為定義新的變數。

要實作在函式中修改外部變數,你需要使用globalnonlocal關鍵字。

命名空間,有效範圍

想要深入了解命名空間和有效範圍,你可以檢視程式設計教學命名空間,有效範圍介紹一節。

下面的函式show並沒有修改模組中定義的message變數,而是定義了自己的message

functions.py
# 在模組中定義變數 message
message = '我是一個模組變數'

# 函式 show 定義了自己的 message def show(): # 這並不會修改模組定義的 message message = '我是函式中的變數' print(message)
# 函式 show_again 使用了模組定義的 message def show_again(): print(message)
show() show_again()
我是函式中的變數
我是一個模組變數

Python 函式註解

書寫 Python 函式的文件字串,可以讓開發人員輕松了解函式的用法,當然這需要開發工具具備相應的程式碼提示功能。

文件字串本質上是書寫在函式中的字串常值,他必須是函式主體的第一行程式碼,可以采用緊密相鄰或加入空白字元的方式進行拼接,比如,'這是一個非常有用的'"函式",但不應包含需要運算的內容或操作,比如,'這是一個非常有用的'+"函式"f'他可以對 {count} 個目標進行計算'

當使用三重引號時,文件字串可以是多行的,字串中的空白字元均會保留,但這僅體現在函式物件的__doc__變數中,開發工具應對空白字元進行處理,以向開發人員展現更加友好的資訊。

如何為 Python 函式的參數和傳回值新增批註?

與函式的文件字串不同,批註主要用於說明函式參數和傳回值的型別,多個型別可以使用|分隔。參數批註的方式為,在參數名稱後書寫:,然後跟隨參數的型別,比如name: str。傳回值批註的方式為,在def陳述式末尾的:之前書寫->,然後跟隨傳回值的型別,比如def hi() -> str | None

所有批註會作為一個字典儲存在函式物件的__annotations__變數中,字典鍵值組的鍵是一個字串,其內容為return(表示傳回值)或參數名稱,鍵值組的值為表示傳回值或參數型別的型別物件。

functions.py
# 一個簡單的函式
def simple(a: int = 1) -> None:
	'''一個簡單的函式~~~!

果然,很簡單。
'''

Python 巢狀函式

巢狀函式是定義在另一個函式或方法中的函式,其采用的語法和普通函式沒有區別,被定義的巢狀函式的可存取性,一般等同於同一命名空間中的變數。

當然,你可以通過傳回值或其他方式,使巢狀函式在更多位置得以呼叫,但這有違定義巢狀函式的初衷。

函式check是定義在函式add_list中的巢狀函式,用於排除元組中大於10的數值。

functions.py
# 計算元組中所有小於等於 10 的數值之和
def add_list(*l):
	# 巢狀函式 check,檢查數值,大於 10 則傳回 0
	def check(i):
		return 0 if i > 10 else i

# 呼叫 check,忽略元組中大於 10 的數值 num = 0 for i in l: num += check(i)
return num
print(add_list(4, 2, 11, 3))
9

Python Lambda 運算式

使用 lambda 運算式,你可以簡便的定義一個匿名函式。與普通的函式不同,lambda 運算式定義的函式,不支援文件字串以及參數或傳回值的批註,並且僅允許單一的運算式,該運算式的運算結果即為函式的傳回值,不需要使用return陳述式。

在下面的程式碼中,我們使用 lambda 運算式定義了一個完成除法運算的匿名函式。

functions.py
# 使用 lambda 運算式定義匿名函式
div = lambda a, b: a / b

print(div(9, 3))
3.0

程式碼

functions.py·codebeatme/python·GitHub