在Python函数定义中,*args
和**kwargs
是两个非常重要的参数收集机制,它们为函数提供了极大的灵活性。本文将全面解析它们的区别、工作原理以及实际应用场景。
*args
(非关键字参数收集)args
,但约定俗成使用args
(*
才是关键)**kwargs
(关键字参数收集)kwargs
,但约定俗成使用kwargs
(**
才是关键)特性 | *args |
**kwargs |
---|---|---|
参数类型 | 收集位置参数 | 收集关键字参数 |
数据结构 | 打包为元组 | 打包为字典 |
符号 | 单星号* |
双星号** |
参数顺序 | 必须出现在关键字参数之前 | 必须出现在*args 之后 |
典型用途 | 处理可变数量的位置参数 | 处理可变数量的关键字参数 |
解包操作 | 可用于解包序列 | 可用于解包字典 |
*args
def sum_numbers(*args):
total = 0
for num in args:
total += num
return total
print(sum_numbers(1, 2, 3)) # 输出: 6
print(sum_numbers(1, 2, 3, 4, 5)) # 输出: 15
当函数被调用时:
args
(或你指定的参数名)*args
必须出现在位置参数之后,关键字参数之前:
def func(a, b, *args, option=True):
print(f"a: {a}, b: {b}, args: {args}, option: {option}")
func(1, 2, 3, 4, 5, option=False)
# 输出: a: 1, b: 2, args: (3, 4, 5), option: False
*
也可用于调用时解包序列:
numbers = [1, 2, 3, 4]
print(sum_numbers(*numbers)) # 输出: 10
**kwargs
def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30, city="New York")
# 输出:
# name: Alice
# age: 30
# city: New York
当函数被调用时:
kwargs
(或你指定的参数名)**kwargs
必须出现在所有参数之后:
def func(a, b, *args, option=True, **kwargs):
print(f"a: {a}, b: {b}, args: {args}, option: {option}, kwargs: {kwargs}")
func(1, 2, 3, 4, 5, option=False, name="Alice", age=30)
# 输出: a: 1, b: 2, args: (3, 4, 5), option: False, kwargs: {'name': 'Alice', 'age': 30}
**
也可用于调用时解包字典:
info = {"name": "Bob", "age": 25, "job": "Developer"}
print_info(**info)
# 输出:
# name: Bob
# age: 25
# job: Developer
*args
和**kwargs
Python函数的参数顺序必须遵循以下规则:
*args
(收集剩余位置参数)**kwargs
(收集剩余关键字参数)def func(a, b, *args, c=10, d=20, **kwargs):
pass
def process_data(name, *scores, report=False, **metadata):
print(f"Student: {name}")
print(f"Scores: {scores}")
print(f"Report: {'Yes' if report else 'No'}")
print("Metadata:")
for k, v in metadata.items():
print(f" {k}: {v}")
process_data("Alice", 85, 90, 78, report=True,
school="Harvard", year=2023, major="CS")
# 输出:
# Student: Alice
# Scores: (85, 90, 78)
# Report: Yes
# Metadata:
# school: Harvard
# year: 2023
# major: CS
def debug(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
@debug
def add(a, b):
return a + b
add(3, 5)
# 输出:
# Calling add with args: (3, 5), kwargs: {}
# add returned: 8
class Parent:
def __init__(self, name, *args, **kwargs):
self.name = name
print(f"Parent args: {args}, kwargs: {kwargs}")
class Child(Parent):
def __init__(self, age, *args, **kwargs):
super().__init__(*args, **kwargs)
self.age = age
child = Child(10, "Alice", school="Harvard")
# 输出: Parent args: (), kwargs: {'school': 'Harvard'}
def call_with_log(func):
def wrapped(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapped
@call_with_log
def complex_operation(x, y, option=False):
return x * y if option else x + y
complex_operation(3, 4, option=True)
# 输出:
# Calling complex_operation
# 返回: 12
# 错误示例
def wrong_func(**kwargs, *args):
pass
# SyntaxError: invalid syntax
def func(a, *args, a=10): # 错误: a重复
pass
# SyntaxError: duplicate argument 'a' in function definition
def func(a, b, **kwargs):
print(a, b, kwargs)
params = {'a': 1, 'b': 2, 'c': 3}
func(**params) # 正常工作
# 输出: 1 2 {'c': 3}
params = {'a': 1, 'b': 2, 'a': 100} # 重复键
func(**params) # 会使用最后的值
# 输出: 100 2 {}
def build_query(table, *conditions, **filters):
query = f"SELECT * FROM {table}"
if conditions:
query += " WHERE " + " AND ".join(conditions)
if filters:
if not conditions:
query += " WHERE "
else:
query += " AND "
query += " AND ".join(f"{k} = {v!r}" for k, v in filters.items())
return query
print(build_query("users", "age > 18", "status = 'active'", country="USA"))
# 输出: SELECT * FROM users WHERE age > 18 AND status = 'active' AND country = 'USA'
def merge_configs(*configs, **overrides):
result = {}
for config in configs:
result.update(config)
result.update(overrides)
return result
default = {'color': 'red', 'size': 10}
user = {'size': 12, 'opacity': 0.8}
final = merge_configs(default, user, color='blue', speed='fast')
print(final)
# 输出: {'color': 'blue', 'size': 12, 'opacity': 0.8, 'speed': 'fast'}
def calculate(operation, *numbers, round_result=False, **options):
if operation == 'sum':
result = sum(numbers)
elif operation == 'product':
result = 1
for n in numbers:
result *= n
elif operation == 'average':
result = sum(numbers) / len(numbers) if numbers else 0
else:
raise ValueError("Unknown operation")
if round_result:
decimals = options.get('decimals', 2)
result = round(result, decimals)
return result
print(calculate('average', 1, 2, 3, 4, round_result=True))
# 输出: 2.5
print(calculate('product', 2, 3, 4, round_result=True, decimals=1))
# 输出: 24.0
*args
**kwargs
*args
→ 关键字参数 → **kwargs
args
/kwargs
(如*paths
, **options
)def func(*args: int, **kwargs: str) -> float:
pass
*args
和**kwargs
是Python灵活参数处理机制的核心,合理使用它们可以写出更通用、更灵活的代码,但同时也要注意不要滥用,以保持代码的可读性和可维护性。