在 Python 中,函數參數的設計非常靈活。
你可以透過位置參數、關鍵字參數、默認參數,甚至可變數量的 *args 和 **kwargs,打造出兼具彈性與可讀性的函數。
然而,這種靈活性同時也伴隨一些陷阱,特別是 可變默認參數,如果不小心踩坑,可能會導致難以追蹤的錯誤。
函數參數的類型
位置參數(Positional Arguments)
根據位置傳遞的參數
def print_name(first_name, last_name):
print(first_name, last_name)
print_name('Jiho', 'Baggins')
關鍵字參數(Keyword Arguments)
根據名稱傳遞的參數
def print_name(first_name, last_name):
print(first_name, last_name)
print_name(last_name='Baggins',
first_name='Jiho')
默認參數(Default Arguments)
具有預設值的參數
def print_name(first_name='Jiho',
last_name='Baggins'):
print(first_name, last_name)
print_name()
案例情境:學校管理系統
假設我們正在開發一個學校管理系統,需要創建一個函數來生成新學生的記錄:
def createStudent(name, age, grades=[]):
return {
'name': name,
'age': age,
'grades': grades
}
這個函數允許我們創建學生記錄,並提供一個空列表作為成績的默認值。

結果
def createStudent(name, age, grades=[]):
return {
'name': name,
'age': age,
'grades': grades
}
def addGrade(student, grade):
student['grades'].append(grade)
print(student['grades'])
# 創建兩個學生
chrisley = createStudent('Chrisley', 15)
dallas = createStudent('Dallas', 16)
# 添加成績
addGrade(chrisley, 90) # 預期: [90]
addGrade(dallas, 100) # 預期: [100],實際: [90, 100]
Dallas 的成績竟然包含了 Chrisley 的分數!
原因解析
Python 在函數定義時就已經建立了默認參數的物件,而不是在函數被呼叫時重新建立。
因此,grades=[]
在多次呼叫間共用同一個列表,導致出現「資料混用」的錯誤。
解決方案:None 模式
def createStudent(name, age, grades=None):
if grades is None:
grades = []
return {
'name': name,
'age': age,
'grades': grades
}
這種模式使用 None 作為特殊標記值,在函數內部創建新的列表。

測試改進後的解決方案
def createStudent(name, age, grades=None):
if grades is None:
grades = []
return {
'name': name,
'age': age,
'grades': grades
}
def addGrade(student, grade):
student['grades'].append(grade)
print(student['grades'])
# 創建兩個學生
chrisley = createStudent('Chrisley', 15)
dallas = createStudent('Dallas', 16)
# 添加成績
addGrade(chrisley, 90) # 輸出: [90]
addGrade(dallas, 100) # 輸出: [100] ✓
現在結果符合預期!每個學生有自己的成績列表。
可變數量的位置參數:*args
def my_function(*args):
print(args)
my_function('Arg1', 245, False)
# 輸出: ('Arg1', 245, False)
星號操作符 * 允許函數接受任意數量的位置參數,這些參數被打包成一個元組。
args 只是一個慣用名稱,你可以使用任何有效的變數名:
def my_function(*values):
print(values)

可變數量的關鍵字參數:**kwargs
def print_data(**data):
print(type(data))
print(data)
print(data.get('anything_goes'))
print_data(this_arg='wowzers',
anything_goes=101)
# 輸出:
#
# {'this_arg': 'wowzers', 'anything_goes': 101}
# 101
雙星號操作符 ** 允許函數接受任意數量的關鍵字參數,這些參數被打包成一個字典。
與 *args 類似,kwargs 也只是一個慣用名稱。
組合使用不同類型的參數
def print_animals(animal1, animal2, *args, animal4, **kwargs):
print(animal1, animal2)
print(args)
print(animal4)
print(kwargs)
print_animals('Snake', 'Fish', 'Guinea Pig', 'Owl',
animal4='Cat', animal5='Dog')
# 輸出:
# Snake Fish
# ('Guinea Pig', 'Owl')
# Cat
# {'animal5': 'Dog'}
參數順序非常重要:
- 標準位置參數
- *args
- 標準關鍵字參數
- **kwargs
結語
掌握函數參數的使用,不只是能讓你的程式「動得起來」,更能讓它「運行得正確、維護得輕鬆」。
從避免可變默認參數的陷阱,到靈活運用 *args
與 **kwargs
,再到結合不同類型的參數設計出高度可擴展的函數,這些技巧能幫助你提升程式的品質與可讀性。