args和kwargs允许函数接收任意数量的位置和关键字参数,分别打包为元组和字典。它们在定义时收集参数,在调用时可通过和解包序列或字典传递参数。混合使用时需遵循参数顺序:普通参数→args→默认参数→*kwargs,避免名称冲突并注意可读性与调试难度。典型应用场景包括通用函数、装饰器和参数转发,能极大提升代码灵活性和复用性。

Python中的
*args
**kwargs
*args
**kwargs
要理解
*args
**kwargs
当你在函数定义中使用
*args
def my_function(*args):
print("收到的位置参数是:", args)
for arg in args:
print(f" - {arg}")
my_function(1, 2, 3)
# 输出:
# 收到的位置参数是: (1, 2, 3)
# - 1
# - 2
# - 3
my_function("hello", "world")
# 输出:
# 收到的位置参数是: ('hello', 'world')
# - hello
# - world类似地,
**kwargs
立即学习“Python免费学习笔记(深入)”;
def another_function(**kwargs):
print("收到的关键字参数是:", kwargs)
for key, value in kwargs.items():
print(f" - {key}: {value}")
another_function(name="Alice", age=30)
# 输出:
# 收到的关键字参数是: {'name': 'Alice', 'age': 30}
# - name: Alice
# - age: 30
another_function(city="New York", zip_code="10001", country="USA")
# 输出:
# 收到的关键字参数是: {'city': 'New York', 'zip_code': '10001', 'country': 'USA'}
# - city: New York
# - zip_code: 10001
# - country: USA当然,你也可以将它们与普通参数以及默认参数混合使用。但这里有个严格的顺序要求:普通参数必须在最前面,然后是
*args
**kwargs
def mixed_function(a, b, *args, c=100, **kwargs):
print(f"a: {a}")
print(f"b: {b}")
print(f"args: {args}")
print(f"c (默认参数): {c}")
print(f"kwargs: {kwargs}")
mixed_function(10, 20, 30, 40, c=50, d="hello", e="world")
# 输出:
# a: 10
# b: 20
# args: (30, 40)
# c (默认参数): 50
# kwargs: {'d': 'hello', 'e': 'world'}可以看到,
10
20
a
b
30
40
*args
c=50
d="hello"
e="world"
**kwargs
*args
**kwargs
在我日常的开发中,
*args
**kwargs
首先,编写通用工具函数。设想你有一个日志记录函数,你希望它能接受任何数量的参数,并把它们打印出来。这时候
*args
import datetime
def log_message(level, *messages, timestamp=True, **extra_info):
"""
一个灵活的日志记录函数。
level: 日志级别 (e.g., 'INFO', 'WARNING')
*messages: 任意数量的要记录的消息
timestamp: 是否添加时间戳 (默认True)
**extra_info: 额外的关键字信息,如'user_id', 'module'
"""
prefix = f"[{level}]"
if timestamp:
prefix = f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} {prefix}"
full_message = " ".join(map(str, messages))
if extra_info:
extra_str = ", ".join([f"{k}={v}" for k, v in extra_info.items()])
print(f"{prefix} {full_message} ({extra_str})")
else:
print(f"{prefix} {full_message}")
log_message("INFO", "用户登录成功", "来自IP", "192.168.1.1", user_id=123, module="Auth")
# 示例输出: 2023-10-27 10:30:00 [INFO] 用户登录成功 来自IP 192.168.1.1 (user_id=123, module=Auth)
log_message("WARNING", "数据库连接失败", timestamp=False)
# 示例输出: [WARNING] 数据库连接失败这个例子就很好地展示了如何用它们来构建一个既通用又可配置的函数。
*messages
timestamp
**extra_info
其次,装饰器(Decorators) 的实现几乎离不开它们。装饰器需要包装任意签名的函数,并保持其原有的参数传递能力。
*args
**kwargs
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs) # 关键:用*args和**kwargs转发参数
end_time = time.time()
print(f"函数 '{func.__name__}' 执行耗时: {end_time - start_time:.4f} 秒")
return result
return wrapper
@timer
def long_running_task(iterations, multiplier=1):
total = 0
for i in range(iterations):
total += i * multiplier
return total
@timer
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
long_running_task(10000000, multiplier=2)
greet("World", greeting="Hi")如果没有
*args
**kwargs
wrapper
最后,函数转发(Function Forwarding)。有时候,一个函数的主要职责就是接收参数,然后把它们原封不动地传递给另一个函数。这在构建API接口或者中间件时很常见。
def process_data(data, config_path, **kwargs):
# 假设这里有一些处理数据的逻辑
print(f"处理数据: {data}, 配置路径: {config_path}")
print(f"额外处理参数: {kwargs}")
# 然后可能调用一个更底层的函数
_internal_processing(data, config_path, **kwargs)
def _internal_processing(data, config_path, timeout=30, debug_mode=False, **extra_settings):
print(f"内部处理中... 数据: {data}, 配置: {config_path}, 超时: {timeout}, 调试模式: {debug_mode}")
print(f"内部额外设置: {extra_settings}")
# ... 实际处理逻辑 ...
process_data("sensor_readings", "/app/config.json", timeout=60, debug_mode=True, user="admin")在这个例子中,
process_data
_internal_processing
*args
**kwargs
在使用
*args
**kwargs
一个最核心的规则就是参数顺序。Python函数定义的参数顺序是固定的:
你看,
*args
**kwargs
*args
SyntaxError
# 错误示例:*args 在普通参数之后,但在关键字参数之前
# def bad_order(a, *args, b):
# pass
# SyntaxError: invalid syntax
# 正确的顺序
def good_order(a, *args, b_kw_only, **kwargs):
print(f"a: {a}")
print(f"args: {args}")
print(f"b_kw_only: {b_kw_only}")
print(f"kwargs: {kwargs}")
good_order(1, 2, 3, b_kw_only="hello", key="value")
# 输出:
# a: 1
# args: (2, 3)
# b_kw_only: hello
# kwargs: {'key': 'value'}这里的
b_kw_only
b_kw_only=...
另一个常见的问题是参数名冲突。如果你在函数定义中有一个明确的关键字参数,例如
def func(name, **kwargs):
**kwargs
name
TypeError
name
def my_profile(name, age, **kwargs):
print(f"Name: {name}, Age: {age}")
print(f"Other info: {kwargs}")
# 这是可以的,'city'不是明确的参数
my_profile("Alice", 30, city="New York")
# 这会报错:'name'参数被指定了两次
try:
my_profile("Bob", 25, name="Robert", occupation="Engineer")
except TypeError as e:
print(f"错误发生: {e}")
# 输出: 错误发生: my_profile() got multiple values for argument 'name'这其实很合理,毕竟你不能同时给一个变量赋两个不同的值。所以在设计函数时,要确保
**kwargs
还有就是可读性问题。过度使用
*args
**kwargs
*args
**kwargs
**kwargs
最后,调试的挑战。当函数签名非常灵活时,调试可能会变得稍微复杂。如果一个错误发生在
*args
**kwargs
*args
**kwargs
*
**
前面我们讨论了
*args
**kwargs
*
**
*1. 使用``解包序列作为位置参数**
当你有一个列表或元组,里面的元素恰好是你想要作为位置参数传递给函数的,这时就可以使用
*
def sum_numbers(a, b, c):
return a + b + c
my_numbers = [10, 20, 30]
# 如果不使用解包,你需要这样写:
# sum_numbers(my_numbers[0], my_numbers[1], my_numbers[2])
# 使用 * 解包列表
result = sum_numbers(*my_numbers)
print(f"解包列表调用结果: {result}") # 输出: 解包列表调用结果: 60
# 也可以是元组
my_tuple = (5, 15, 25)
result_tuple = sum_numbers(*my_tuple)
print(f"解包元组调用结果: {result_tuple}") # 输出: 解包元组调用结果: 45这个特性非常有用,比如你从数据库查询得到了一行数据(通常是元组或列表),然后想把这行数据作为参数传递给一个处理函数。
2. 使用``解包字典作为关键字参数**
当你有一个字典,其中的键值对正好对应了函数需要接收的关键字参数,那么
**
key=value
def create_user(name, age, city="Unknown", email=None):
print(f"创建用户: {name}, 年龄: {age}, 城市: {city}, 邮箱: {email}")
user_data = {
"name": "Charlie",
"age": 40,
"city": "London"
}
# 不使用解包,你需要这样写:
# create_user(name=user_data["name"], age=user_data["age"], city=user_data["city"])
# 使用 ** 解包字典
create_user(**user_data)
# 输出: 创建用户: Charlie, 年龄: 40, 城市: London, 邮箱: None
# 字典中可以包含函数签名中没有的键,它们会被 **kwargs 捕获(如果函数定义有 **kwargs)
def process_settings(timeout=30, retries=3, **extra_options):
print(f"Timeout: {timeout}, Retries: {retries}")
print(f"Extra options: {extra_options}")
settings = {
"timeout": 60,
"retries": 5,
"log_level": "DEBUG",
"user_id": 101
}
process_settings(**settings)
# 输出:
# Timeout: 60, Retries: 5
# Extra options: {'log_level': 'DEBUG', 'user_id': 101}这在处理配置信息、API请求参数或者从JSON/YAML文件加载的设置时特别方便。
*3. `
和
你当然可以将这两种解包方式结合起来,甚至与普通参数一起使用。这给了你极大的灵活性来构造函数调用。
def configure_system(system_id, *components, admin_email, **settings):
print(f"系统ID: {system_id}")
print(f"组件: {components}")
print(f"管理员邮箱: {admin_email}")
print(f"系统设置: {settings}")
# 准备参数
system_components = ["web_server", "database", "cache"]
system_settings = {
"max_connections": 100,
"logging_level": "INFO",
"debug_mode": True
}
# 组合调用
configure_system(
"SYS_001",
*system_components, # 解包列表作为位置参数
"monitoring_agent", # 额外的普通位置参数以上就是python怎么使用*args和kwargs参数_python *args与kwargs参数用法详解的详细内容,更多请关注php中文网其它相关文章!
python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号