Python function receiving multiple arguments of different types being packed into a tuple

Python Function Arguments (15):避免陷阱,設計更完美的函數

在 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
    }

這個函數允許我們創建學生記錄,並提供一個空列表作為成績的默認值。

School management system interface showing student records with names, ages, and grades fields

結果

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 作為特殊標記值,在函數內部創建新的列表。

Safe Python code with None default parameter creating a new list each time

測試改進後的解決方案

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)
Python function receiving multiple arguments of different types being packed into a tuple

可變數量的關鍵字參數:**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'}

參數順序非常重要:

  1. 標準位置參數
  2. *args
  3. 標準關鍵字參數
  4. **kwargs

結語

掌握函數參數的使用,不只是能讓你的程式「動得起來」,更能讓它「運行得正確、維護得輕鬆」。

從避免可變默認參數的陷阱,到靈活運用 *args**kwargs,再到結合不同類型的參數設計出高度可擴展的函數,這些技巧能幫助你提升程式的品質與可讀性。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

High Quality

Lorem ipsum dolor sit amet, consectetur adipiscing elitsed do eiusmod tempor.

Fast Delivery

Lorem ipsum dolor sit amet, consectetur adipiscing elitsed do eiusmod tempor.

Best Warranty

Lorem ipsum dolor sit amet, consectetur adipiscing elitsed do eiusmod tempor.