函式#

函式是一段可重複使用的程式碼,用 def 關鍵字定義,呼叫時執行函式內的程式,達到「寫一次、多次使用」的效果。 Python 的函式支援預設參數、關鍵字引數、可變參數,以及作為一級物件傳遞與回傳。


定義與呼叫函式#

1
2
3
4
5
6
7
# 定義函式
def greet(name):
    print(f"Hello, {name}!")

# 呼叫函式
greet("Alice")   # Hello, Alice!
greet("Bob")     # Hello, Bob!

回傳值(return)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def add(a, b):
    return a + b

result = add(3, 5)
print(result)  # 8

# 可以回傳多個值(實際上回傳的是 tuple)
def min_max(numbers):
    return min(numbers), max(numbers)

lo, hi = min_max([3, 1, 4, 1, 5, 9])
print(lo, hi)  # 1 9

# 沒有 return 或 return 無值時,回傳 None
def do_nothing():
    pass

result = do_nothing()
print(result)  # None

參數類型#

位置參數(Positional Arguments)#

1
2
3
4
def describe(name, age, city):
    print(f"{name}{age} 歲,住在 {city}")

describe("Alice", 25, "Taipei")  # 按順序傳入

預設參數(Default Arguments)#

1
2
3
4
5
6
def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet("Alice")           # Hello, Alice!
greet("Bob", "Hi")       # Hi, Bob!
greet("Charlie", greeting="Hey")  # Hey, Charlie!

注意 :預設參數必須放在非預設參數的 後面

關鍵字參數(Keyword Arguments)#

1
2
3
4
5
def describe(name, age, city):
    print(f"{name}{age} 歲,住在 {city}")

# 用關鍵字傳入,順序可以不同
describe(age=25, city="Taipei", name="Alice")

*args:接受任意數量的位置參數#

1
2
3
4
5
6
def total(*args):
    print(args)   # 收到的是 tuple
    return sum(args)

print(total(1, 2, 3))        # 6
print(total(1, 2, 3, 4, 5))  # 15

**kwargs:接受任意數量的關鍵字參數#

1
2
3
4
5
6
7
8
9
def print_info(**kwargs):
    print(kwargs)  # 收到的是 dict
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=25, city="Taipei")
# name: Alice
# age: 25
# city: Taipei

組合使用#

1
2
3
4
5
6
7
def flexible(required, *args, default="hello", **kwargs):
    print(f"必要參數:{required}")
    print(f"額外位置參數:{args}")
    print(f"預設參數:{default}")
    print(f"額外關鍵字參數:{kwargs}")

flexible("必填", 1, 2, 3, default="world", x=10, y=20)

變數作用域(Scope)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
x = 10  # 全域變數

def foo():
    x = 20  # 局部變數,不影響全域的 x
    print(x)  # 20

foo()
print(x)  # 10

# 若要在函式內修改全域變數,用 global
def bar():
    global x
    x = 30

bar()
print(x)  # 30

Lambda 函式(匿名函式)#

Lambda 是一種簡短的 單行函式 ,常搭配 sorted()map()filter() 使用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 語法:lambda 參數: 表達式
square = lambda x: x ** 2
print(square(5))  # 25

add = lambda a, b: a + b
print(add(3, 4))  # 7

# 搭配 sorted()
words = ["banana", "apple", "cherry", "kiwi"]
sorted_words = sorted(words, key=lambda w: len(w))
print(sorted_words)  # ['kiwi', 'apple', 'banana', 'cherry']

# 搭配 sorted() 對字典串列排序
students = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78},
]
by_score = sorted(students, key=lambda s: s["score"], reverse=True)
for s in by_score:
    print(f"{s['name']}: {s['score']}")

常用高階函式#

高階函式(Higher-Order Function)是指接受「函式」作為參數的函式。Lambda 最常見的用途就是作為這類函式的引數:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# map():對每個元素套用函式
squares = list(map(lambda x: x ** 2, numbers))
print(squares)   # [1, 4, 9, 16, 25]

# filter():篩選滿足條件的元素
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)     # [2, 4, 6, 8, 10]

# sorted():自訂排序規則
words = ["banana", "apple", "cherry", "kiwi"]
by_length = sorted(words, key=lambda w: len(w))
print(by_length) # ['kiwi', 'apple', 'banana', 'cherry']

map()filter()sorted() 的完整說明(多序列、多條件排序、進階用法)請見 CH11:常用內建函式


閉包(Closure)#

函式可以記住外部函式的變數:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def make_multiplier(factor):
    def multiplier(x):
        return x * factor  # 記住了 factor
    return multiplier

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))  # 10
print(triple(5))  # 15

遞迴(Recursion)#

函式可以呼叫自己:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

print(factorial(5))  # 120(5 × 4 × 3 × 2 × 1)

# 費波那契數列
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

for i in range(10):
    print(fibonacci(i), end=" ")
# 0 1 1 2 3 5 8 13 21 34

實戰範例#

計算移動平均#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def moving_average(prices, window):
    """計算移動平均線"""
    result = []
    for i in range(len(prices) - window + 1):
        avg = sum(prices[i:i + window]) / window
        result.append(round(avg, 2))
    return result

prices = [100, 102, 98, 105, 110, 108, 112]
ma3 = moving_average(prices, 3)
print(ma3)  # [100.0, 101.67, 104.33, 107.67, 110.0]

快速排序#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)

data = [3, 6, 8, 10, 1, 2, 1]
print(quicksort(data))  # [1, 1, 2, 3, 6, 8, 10]