python的方法的參數除了可以使用標識符,還可以使用***作為參數,這些符號在Python中常用於處理可變數量的參數(也稱為“可變參數”或“星號參數”)。

注意:*通常與變量名結合使用,如*args(表示任意數量的位置參數);**通常如**kwargs(表示任意數量的關鍵字參數)。這些名字是慣例,不是必須的,可以用其他名字替換。

1. * 的用法(可變位置參數)

  • 在函數定義中* 用於收集任意數量的位置參數(positional arguments),這些參數會被打包成一個元組(tuple)。這允許函數接受不定數量的參數,而無需預先指定。
  • 語法:def func(固定參數, *args): ...
  • *args 收集所有多餘的位置參數。
  • 位置:*args 必須在固定位置參數之後,在**kwargs之前(如果有)。
  • 在函數調用中* 用於“展開”(unpack)一個可迭代對象(如列表、元組),將其元素作為位置參數傳入函數。
  • 語法:func(*iterable)
  • 這相當於將iterable的每個元素逐個作為位置參數傳遞。
示例(定義和調用結合)
# 函數定義中使用 *
def sum_numbers(*args):
    total = 0
    for num in args:  # args是一個元組
        total += num
    return total

# 調用:直接傳入多個位置參數
print(sum_numbers(1, 2, 3))  # 輸出: 6  (args = (1, 2, 3))

# 函數調用中使用 * 展開
numbers = [4, 5, 6]  # 列表
print(sum_numbers(*numbers))  # 輸出: 15  (相當於 sum_numbers(4, 5, 6))

2. ** 的用法(可變關鍵字參數)

  • 在函數定義中** 用於收集任意數量的關鍵字參數(keyword arguments),這些參數會被打包成一個字典(dict)。鍵是參數名,值是參數值。
  • 語法:def func(固定參數, **kwargs): ...
  • **kwargs 收集所有多餘的關鍵字參數。
  • 位置:**kwargs 必須在所有其他參數之後(包括*args)。
  • 在函數調用中** 用於“展開”一個字典,將其鍵值對作為關鍵字參數傳入函數。
  • 語法:func(**dictionary)
  • 這相當於將字典的每個鍵值對作為 key=value 形式傳遞。
示例(定義和調用結合)
# 函數定義中使用 **
def print_info(**kwargs):
    for key, value in kwargs.items():  # kwargs是一個字典
        print(f"{key}: {value}")

# 調用:直接傳入多個關鍵字參數
print_info(name="Alice", age=30, city="New York")
# 輸出:
# name: Alice
# age: 30
# city: New York

# 函數調用中使用 ** 展開
info = {"name": "Bob", "age": 25, "city": "London"}
print_info(**info)  # 相當於 print_info(name="Bob", age=25, city="London")
# 輸出同上

3. 同時使用 ***

  • 在函數定義中:可以同時使用*args**kwargs,以處理不定數量的位置參數和關鍵字參數。
  • 順序必須是:固定位置參數 → *args → 固定關鍵字參數 → **kwargs
  • 這允許函數非常靈活,能接受各種參數組合。
  • 在函數調用中:可以同時使用*展開位置參數和**展開關鍵字參數。
  • 語法:func(*iterable, **dictionary)
  • 注意:展開的位置參數必須在關鍵字參數之前(Python的調用規則)。
  • 原理:在定義中,***允許函數“捕獲”額外參數;在調用中,它們允許“注入”參數。這常用於裝飾器、API函數或需要轉發參數的場景。
詳細代碼示例:同時使用 ***(定義和調用)
# 示例1: 函數定義中同時使用 * 和 **
def flexible_func(a, b, *args, **kwargs):
    print(f"固定位置參數: a={a}, b={b}")
    print(f"可變位置參數 (*args): {args}")  # 元組
    print(f"可變關鍵字參數 (**kwargs): {kwargs}")  # 字典
    
    # 可以進一步處理args和kwargs
    total = a + b + sum(args)
    for key, value in kwargs.items():
        print(f"額外信息: {key} = {value}")
    return total

# 調用方式1: 直接傳入參數
result = flexible_func(1, 2, 3, 4, name="Alice", age=30)
print(f"結果: {result}")
# 輸出:
# 固定位置參數: a=1, b=2
# 可變位置參數 (*args): (3, 4)
# 可變關鍵字參數 (**kwargs): {'name': 'Alice', 'age': 30}
# 額外信息: name = Alice
# 額外信息: age = 30
# 結果: 10  (1+2+3+4)

# 調用方式2: 使用 * 和 ** 展開傳入
pos_args = [1, 2, 3, 4]  # 列表作為位置參數
kw_args = {"name": "Bob", "age": 25}  # 字典作為關鍵字參數
result = flexible_func(*pos_args, **kw_args)  # 相當於 flexible_func(1, 2, 3, 4, name="Bob", age=25)
print(f"結果: {result}")
# 輸出同上,但 kwargs={'name': 'Bob', 'age': 25},結果仍為10

# 示例2: 更復雜的場景(參數轉發)
def wrapper_func(*args, **kwargs):
    # 將所有參數轉發給另一個函數
    return flexible_func(*args, **kwargs)

# 調用wrapper_func,它會轉發
result = wrapper_func(5, 6, 7, city="Tokyo", country="Japan")
print(f"結果: {result}")
# 輸出:
# 固定位置參數: a=5, b=6
# 可變位置參數 (*args): (7,)
# 可變關鍵字參數 (**kwargs): {'city': 'Tokyo', 'country': 'Japan'}
# 額外信息: city = Tokyo
# 額外信息: country = Japan
# 結果: 18  (5+6+7)
另一個綜合示例:混合固定參數和可變參數
def order_food(main_dish, *sides, **options):
    print(f"主菜: {main_dish}")
    print(f"配菜: {sides}")
    print(f"選項: {options}")

# 直接調用
order_food("Pizza", "Fries", "Salad", size="Large", drink="Coke")
# 輸出:
# 主菜: Pizza
# 配菜: ('Fries', 'Salad')
# 選項: {'size': 'Large', 'drink': 'Coke'}

# 展開調用
sides_list = ["Fries", "Salad"]
options_dict = {"size": "Large", "drink": "Coke"}
order_food("Pizza", *sides_list, **options_dict)  # 同上輸出

注意事項

  • 順序規則
  • 定義時:位置參數 → *args → 關鍵字參數 → **kwargs
  • 調用時:位置參數(包括*展開)必須在關鍵字參數(包括**展開)之前。
  • Python版本差異:Python 3.5+ 支持更多靈活性,如僅位置參數(/)和僅關鍵字參數(*),但基本用法不變。
  • 常見錯誤
  • 如果*args接收到關鍵字參數,會報錯(TypeError)。
  • 展開時,確保iterable是可迭代的,dictionary的鍵必須是字符串。
  • 不要在定義中重複使用***(如兩個*args)。
  • 實際應用:常用於庫函數(如print(*objects, sep=' '))、裝飾器或需要處理未知參數的函數。