Python 入門指南 5.0

單元 10 - 函數

~~學習進度表~~

函數 (function) 是一種功能性的程式碼集合,可以將程式 (program) 分割成小部分,藉由呼叫 (call) 函數安排執行順序

def function_name():
    pass

定義函數使用關鍵字 (keyword) def ,其後空一格接函數名稱與小括弧,小括弧用來放參數列 (parameter list) ,函數可以有參數 (parameter) 也可以沒有參數,沒有參數的函數的小括弧留空,另外函數可用 return 設定回傳值 (return value) ,沒有回傳值的函數也就不需要 return 。舉一例如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 計算參數總合
def my_sum(a, b):
    # 回傳參數相加結果
    return a + b

# 利用整數當參數
print(my_sum(33, 22))
# 利用字串當參數
print(my_sum("Hello", "World"))

# 檔名: function_demo01.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

my_sum() 函數回傳兩個參數的相加值,參數名稱及數量則是依自己定義放在參數列,這裡的參數用了 ab ,另外此例用了一個 return ,這裡 return 就是函數結束執行,將控制權交還原本呼叫函數的地方

 2
 4
def my_sum(a, b):
    return a + b

此例先計算 3322 的合,然後印出計算結果

 9
print(my_sum(33, 22))

接下來則是連接 "Hello""World" ,加號用在字串 (string) 是把兩個字串連接起來

 7
print(print(my_sum("Hello", "World"))

執行結果如下

$ python function_demo01.py
55
HelloWorld
$

函數參數可以有預設值,參數預設值是用等號在參數列直接指派數值,例如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 計算參數總合
def my_sum(a = 0, b = 0):
    # 回傳參數相加結果
    return a + b

# 利用關鍵字引數設定參數
print(my_sum(b = 33, a = 22))
# 不提供參數
print(my_sum())

# 檔名: function_demo02.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

這裡在參數列直接指派數值給參數 ab

 2
def my_sum(a = 0, b = 0):

因此呼叫時可以不提供參數,會以預設值代入

 9
print(my_sum())

執行結果如下

$ python function_demo02.py
55
0
$

呼叫函數時可以依參數位置逐一提供參數,或是用關鍵字引數 (keyword argument) 呼叫,在參數列加入斜線 / 或星號 * 等可以限制呼叫方式,或是混用兩種方式,例如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 只能用參數位置呼叫
def my_sum1(a, b, /):
    # 回傳參數相加結果
    return a + b

# 只能有關鍵字引數呼叫
def my_sum2(*, a, b):
    # 回傳參數相加結果
    return a + b

# 兩種呼叫方式混合
def my_sum3(a, /, *, b):
    # 回傳參數相加結果
    return a + b

# 印出 11
print(my_sum1(5, 6))
# 印出 22
print(my_sum2(b = 11, a = 11))
# 印出 33
print(my_sum3(11, b = 22))

# 檔名: function_demo03.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

引數的英文原文為 argument ,參數的英文原文為 parameter ,所謂引數是呼叫函數時提供的實際數值,參數則是定義函數時所用的識別字名稱,兩者其實是同一件事情,之所以會有兩種名稱,這是由於英文的語言習慣是每個地方都要有專門的名詞,在此基於教學立場,除了關鍵字引數為 Python 官方文件的用詞外,其他會統稱為參數,至於引數可能會以參數值統稱。

同一件事情用不同的名詞在英文中屢見不鮮,像是在程式設計領域後面還會碰到 process 一詞, process 通常翻譯成行程,意思是正在被執行的程式,所以是程式原文 program 的進行式狀態名詞,那程式就是寫好還沒有被執行的檔案,然後詳細深入作業系統討論會嚴格把兩者區分,這裡我們在初學一率統稱 program ,也就是程式,因為要用不同詞彙去討論同一件事情的不同面向,這不是初學程式設計馬上能理解的。

斜線 / 必須放在限制位置呼叫參數的最後,例如 my_sum1() 參數列的最後是斜線 / ,表示 ab 都必須以位置呼叫,也就是呼叫時提供的第一個參數為 a ,第二個為 b

 2
 4
def my_sum1(a, b, /):
    return a + b

實際呼叫就是預設的方式,但限制只能用這種方式

17
print(my_sum1(5, 6))

星號 * 必須放在關鍵字引數呼叫參數的開頭,例如 my_sum2() 參數列的開頭是星號 * ,表示 ab 都必須以關鍵字引數呼叫,也就是呼叫時必須以參數名稱設定

 7
 9
def my_sum1(a, b, /):
    return a + b

實際呼叫限制使用關鍵字呼叫,呼叫的順序則沒有限制

19
print(my_sum2(b = 11, a = 11))

如果參數列定義沒有加上斜線 / 或星號 * ,就可以混用位置呼叫或是關鍵字引數呼叫,但是一樣位置呼叫在前,關鍵字引數呼叫在後。

兩者標記也可以混用,斜線 / 之前限制位置呼叫,星號 * 之後為關鍵字引數呼叫

12
14
def my_sum3(a, /, *, b):
    return a + b

位置呼叫直接提供參數值,關鍵字引數呼叫則要加上參數名稱與等號

21
print(my_sum3(11, b = 22))

執行結果如下

$ python function_demo03.py
11
22
33
$

參數數量也可以不受限制,在參數識別字前加上一個星號 * 表示參數為序對 (tuple) ,要以位置參數呼叫,加上兩個星號表示字典 (dictionary) ,要以關鍵字引數呼叫,例如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 不限個數參數的序對版本
def my_sum1(*arg):
    # 印出參數型態
    print(type(arg))
    # 暫存回傳結果
    result = 0
    # 依參數計算總合
    for i in arg:
        result += i
    # 回傳參數總合
    return result

# 不限個數參數的字典版本
def my_sum2(**arg):
    # 印出參數型態
    print(type(arg))
    # 暫存回傳結果
    result = 0
    # 依參數計算總合
    for i in arg:
        result += arg[i]
    # 回傳參數總合
    return result

# 利用位置提供參數
print(my_sum1(11, 22, 33))
# 利用關鍵字引數設定參數
print(my_sum2(a = 11, b = 22, c = 33))

# 檔名: function_demo04.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

my_sum1()my_sum2() 的內容幾乎相同,都是先用內建函數 type() 印出參數的型態 (type) ,然後利用 for 迴圈 (loop) 替參數加總,最後回傳參數的所有相加值,處理上除了 my_sum1() 是序對外, my_sum2() 由於是字典,所以 for 迴圈的 i 是取得 key

20
21
    for i in arg:
        result += arg[i]

呼叫時關鍵字引數中等號左邊的關鍵字會是 key

26
28
print(my_sum1(11, 22, 33))
print(my_sum2(a = 11, b = 22, c = 33))

執行結果如下

$ python function_demo04.py
<class 'tuple'>
66
<class 'dict'>
66
$

關鍵字 lambda 可以定義簡單的運算式 (expression) ,在函數需要以函數當作參數時,可以替代函數函數當作參數,以下簡單示範使用 lambda

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 變數 sum 是 lambda 定義的無名函數
my_sum = lambda x, y: x + y
# 印出 33
print(my_sum(11, 22))

# 檔名: function_demo05.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

此例 lambda 的定義指派給變數 my_summy_sum 就變成需要參數才能使用的函數

2
my_sum = lambda x, y: x + y

lambda 定義出的運算式也被稱為無名函數 (anonymous function) 。

執行結果如下

$ python function_demo05.py
33
$

關鍵字 yield 用在函數中可以定義產生器 (generator) 函數,例如

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 定義產生器函數
def number(*arg):
    for i in range(len(arg)):
        # 依次產生引數值
        yield arg[i]

# 印出產生器函數的計算結果
print(sum(number(11, 22, 33)))
# 印出產生器運算式的計算結果
print(sum(i for i in [11, 22, 33]))

# 檔名: function_demo06.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月

所謂產生器就是依序產生數值的意思,至於產生數值的規則可以自訂,此例是依序讓 number() 產生序對中的參數值

 2
 3
 5
def number(*arg):
    for i in range(len(arg)):
        yield arg[i]

底下用內建函數 sum() 對參數進行加總,注意第 8 行是由產生器函數產生的數值

 8
print(sum(number(11, 22, 33)))

第 10 行則是產生器運算式 (generator expression) 產生的數值

10
print(sum(i for i in [11, 22, 33]))

關鍵字 for 之前的變數 i 就會產生的數值,此變數 i 就是由 for 在關鍵字 in 後面取得的串列元素,這裡是整數,因此會依次產生 112233sum() 計算。

產生器的目的是產生數列中的數值,產生器運算式是簡單的產生器寫法,用 for 迴圈直接在複合資料型態 (compound data type) 中取得數值,就是相對數值已經建立好,或是還需額外放在函數中計算,總之是產生器函數的語法糖,而產生器其實也是迭代器 (iterator) 的語法糖,我們會在單元 14 介紹迭代器。

上例執行結果如下

$ python function_demo06.py
66
66
$

函數是模組化 (modular design) 程式設計的第一步,繼續模組化程式設計就是要來介紹類別 (class) ,不過在進入類別之前,我們先來進一步討論一下指派運算 (assignment expression) 。

中英文術語對照
無名函數anonymous function
指派運算assignment expression
呼叫call
複合資料型態compound data type
類別class
字典dictionary
運算式expression
函數function
產生器generator
產生器運算式generator expression
迭代器iterator
關鍵字keyword
關鍵字引數keyword argument
迴圈loop
模組化modular design
參數列parameter list
參數parameter
程式program
回傳值return value
序對tuple
型態type
重點整理
1. 函數是一種功能性的程式碼集合,可以有參數及回傳值,參數不限個數,回傳值最多只能有一個。
2. return 陳述將執行控制權還給呼叫函數的地方。
3. 如果要給函數的參數設定預設值,就直接在參數列用等號指派數值,呼叫時就可以不提供參數。
4. 呼叫函數提供參數時,可以依照參數列順序或是利用關鍵字引數,如果要限制呼叫方式會混用兩者,需要借助 /*
5. 參數可以不限制數量,在參數前加上星號會取得序對,並限制依順序呼叫,若是加上兩個星號表示字典,限制用關鍵字引數呼叫。
6. lambda 運算式可以定義簡單的無名函數。
7. 函數中用 yield 而非 return 就是產生器函數。
8. 產生器運算式是產生器函數的簡化寫法。
問題與討論
1. 為什麼函數要有參數?若在函數中改變參數的值,原本的參數會被改變嗎?
2. 為什麼函數只能有一個回傳值?如果有需要回傳多個數值該如何處理?
3. 要怎麼替函數的參數設定預設值?
4. 要怎麼限制函數的參數要按照順序提供?或是限制使用關鍵字引數?
5. 什麼是無名函數?為什麼要使用無名函數?
5. 什麼是產生器函數?
練習
1. 寫一個程式 exercise1001.py ,裡頭設計一個函數 my_sum() ,用以計算兩個整數的和。 參考程式碼
2. 承上題,另寫一個程式 exercise1002.py ,改成接受使用者輸入的版本。 參考程式碼
3. 寫一個程式 exercise1003.py ,裡頭設計一個函數 my_sum() ,只用一個整數參數 p ,結果回傳 1p 之間所有正整數的和。 參考程式碼
4. 承上題,另寫一個程式 exercise1004.py ,改成接受使用者輸入的版本。 參考程式碼
5. 寫一個程式 exercise1005.py ,裡頭設計一個函數 factorial() ,用以計算階乘值。 參考程式碼
6. 承上題,另寫一個程式 exercise1006.py ,改成接受使用者輸入的版本。 參考程式碼
7. 寫一個程式 exercise1007.py ,裡頭設計一個函數 fibonacci() ,用以計算費氏數列。 參考程式碼
8. 承上題,另寫一個程式 exercise1008.py ,改成接受使用者輸入的版本。 參考程式碼
9. 寫一個程式 exercise1009.py ,設計印出時間的 print_time() 函數,參數 now 的值預設為 None ,並在函數中確認 None 有值,如果沒有值就指派為現在時間。 參考程式碼
10. 寫一個程式 exercise1010.py ,設計一個至少需要三個參數的函數,例如 do_something() ,然後在函數內依據函數的值回傳計算結果,計算方式請自行定義,最後利用關鍵字引數呼叫並印出回傳值。 參考程式碼
11. 承上題,將程式寫在 exercise1011.py 中,將參數改為限制位置呼叫。 參考程式碼
12. 承上題,將程式寫在 exercise1012.py 中,將參數改為限制用關鍵數引數呼叫。 參考程式碼
13. 承上題,將程式寫在 exercise1013.py 中,將參數改為混用位置與關鍵數引數呼叫。 參考程式碼
14. 寫一個程式 exercise1014.py ,設計函數採用序對的不限個數參數,然後在函數中印出每個參數。 參考程式碼
15. 承上題,將程式寫在 exercise1015.py 中,改用字典的不限個數參數,然後在函數中增加新的 key:value ,例如 a["z"] = "end" ,最後回傳參數 a ,然後在底下執行部分印出每個 keyvalue參考程式碼
16. 關鍵字 lambda 通常會用在需要函數當作參數的場合,將程式寫在 exercise1016.py 中,,設計一個具有兩個序對組合的串列,例如 [(12, "A01"), (9, "B33"), (2, "C02")] ,然後利用內建函數 sorted() 進行排序,用 lambda 設定關鍵字引數 key ,使其用序對中的第二個元素進行排序。 參考程式碼
17. 承練習 5 ,將新程式寫在 exercise1017.py 中,把計算階乘的函數改為產生器函數。 參考程式碼
18. 承練習 7 ,將新程式寫在 exercise1018.py 中,把計算費氏數列的函數改為產生器函數。 參考程式碼

上一頁 單元 9 - 序列、字典與集合
回 Python 入門指南 5.0 首頁
下一頁 單元 11 - 進一步講指派與相等運算
回 Python 教材首頁
回程式語言教材首頁