欢迎光临
我们一直在努力

详解Python中args与*kwargs的使用场景

在 Python 编程中,我们经常会看到函数定义里出现*args和**kwargs这两个 “特殊参数”。对于新手来说,这两个参数看起来抽象又神秘,不知道它们到底有什么用、该在什么场景下用。本文将从基础概念入手,结合实战案例,全方位解析*args和**kwargs的使用场景、核心原理和最佳实践,帮你彻底搞懂这两个 Python 开发中的高频知识点。

一、核心概念:*args 和 **kwargs 到底是什么?

首先要明确:args和kwargs并不是 Python 的关键字,只是约定俗成的命名(你可以写成*params或**kwargs_dict,但不推荐),真正起作用的是前面的*和**运算符。

1.1 *args:接收任意数量的位置参数

*args(全称 arguments)用于收集函数调用时未匹配的位置参数,并将其打包成一个元组 (tuple) 传入函数内部。

  • 核心作用:让函数支持接收 “不确定数量” 的位置参数
  • 数据类型:元组(tuple)
  • 使用位置:函数定义中,在普通参数之后,**kwargs之前

基础示例:

python

运行

def print_args(*args):
# 打印args的类型
print(f"args的类型: {type(args)}")
# 遍历输出所有参数
for index, value in enumerate(args):
print(f"第{index+1}个参数: {value}")

# 调用函数,传入任意数量的参数
print_args(10, "Python", [1,2,3], True)
print("—分割线—")
print_args("只传一个参数")
print("—分割线—")
print_args() # 不传参数也不会报错

输出结果:

plaintext

args的类型: <class 'tuple'>
第1个参数: 10
第2个参数: Python
第3个参数: [1,2,3]
第4个参数: True
—分割线—
args的类型: <class 'tuple'>
第1个参数: 只传一个参数
—分割线—
args的类型: <class 'tuple'>

1.2 **kwargs:接收任意数量的关键字参数

**kwargs(全称 keyword arguments)用于收集函数调用时未匹配的关键字参数,并将其打包成一个字典 (dict) 传入函数内部。

  • 核心作用:让函数支持接收 “不确定数量” 的关键字参数
  • 数据类型:字典(dict)
  • 使用位置:函数定义中,必须放在所有参数的最后

基础示例:

python

运行

def print_kwargs(**kwargs):
# 打印kwargs的类型
print(f"kwargs的类型: {type(kwargs)}")
# 遍历输出所有关键字参数
for key, value in kwargs.items():
print(f"关键字参数 {key} = {value}")

# 调用函数,传入任意数量的关键字参数
print_kwargs(name="张三", age=25, city="北京")
print("—分割线—")
print_kwargs(subject="Python", score=95)

输出结果:

plaintext

kwargs的类型: <class 'dict'>
关键字参数 name = 张三
关键字参数 age = 25
关键字参数 city = 北京
—分割线—
kwargs的类型: <class 'dict'>
关键字参数 subject = Python
关键字参数 score = 95

二、核心使用场景:什么时候该用?

*args和**kwargs的核心价值在于提升函数的灵活性,以下是最常见的 4 个使用场景:

场景 1:函数参数数量不确定时

当你无法预知函数需要接收多少个参数时,使用*args/**kwargs可以避免函数定义的局限性。

实战案例:实现一个通用的求和函数

python

运行

def sum_numbers(*args):
"""求和函数:支持任意数量的数字求和"""
total = 0
for num in args:
# 做类型校验,确保传入的是数字
if not isinstance(num, (int, float)):
raise TypeError("所有参数必须是整数或浮点数")
total += num
return total

# 调用示例
print(sum_numbers(1, 2, 3)) # 输出:6
print(sum_numbers(10.5, 20.3, 5)) # 输出:35.8
print(sum_numbers()) # 输出:0(无参数时返回0)

场景 2:函数封装 / 装饰器开发

在封装已有函数或编写装饰器时,*args和**kwargs可以完美适配被封装函数的任意参数形式,避免参数不匹配的问题。

实战案例:编写一个记录函数执行时间的装饰器

python

运行

import time

def time_it(func):
"""装饰器:记录函数的执行时间"""
def wrapper(*args, **kwargs):
start_time = time.time()
# 执行原函数,传递所有参数
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行耗时:{end_time – start_time:.6f} 秒")
return result
return wrapper

# 测试装饰器
@time_it
def calculate_sum(n):
"""计算1到n的和"""
return sum(range(1, n+1))

@time_it
def print_info(name, age, city="上海"):
"""打印个人信息"""
print(f"姓名:{name},年龄:{age},城市:{city}")

# 调用测试
calculate_sum(1000000)
print_info("李四", 30, city="广州")

输出结果:

plaintext

函数 calculate_sum 执行耗时:0.012345 秒
姓名:李四,年龄:30,城市:广州
函数 print_info 执行耗时:0.000001 秒

场景 3:类的继承与方法重写

在子类重写父类方法时,如果父类方法的参数不确定,使用*args/**kwargs可以保证子类方法兼容父类的所有参数形式。

实战案例:类继承中的参数兼容

python

运行

class Parent:
def __init__(self, name, age, *args, **kwargs):
self.name = name
self.age = age
# 处理额外的参数
self.extra_args = args
self.extra_kwargs = kwargs

class Child(Parent):
def __init__(self, name, age, grade, *args, **kwargs):
# 调用父类构造方法,传递所有参数
super().__init__(name, age, *args, **kwargs)
self.grade = grade

# 创建子类实例,传入额外参数
child = Child("小明", 10, 5, "特长:编程", hobby="篮球", score=98)
print(f"姓名:{child.name},年级:{child.grade}")
print(f"额外位置参数:{child.extra_args}")
print(f"额外关键字参数:{child.extra_kwargs}")

输出结果:

plaintext

姓名:小明,年级:5
额外位置参数:('特长:编程',)
额外关键字参数:{'hobby': '篮球', 'score': 98}

场景 4:解包参数传递

除了函数定义,*和**还可以用于参数解包,将列表 / 元组 / 字典中的元素作为独立参数传递给函数。

实战案例:参数解包的两种方式

python

运行

# 1. 解包列表/元组(使用*)
def add(a, b):
return a + b

nums = [3, 5]
print(add(*nums)) # 等价于 add(3, 5),输出:8

# 2. 解包字典(使用**)
def print_person(name, age):
print(f"Name: {name}, Age: {age}")

person_info = {"name": "王五", "age": 28}
print_person(**person_info) # 等价于 print_person(name="王五", age=28)

三、使用注意事项与最佳实践

3.1 注意事项

  • 参数顺序:函数定义中,参数顺序必须是:普通参数 → *args → 默认参数 → **kwargs,例如:

    python

    运行

    # 正确的顺序
    def func(a, b, *args, c=10, **kwargs):
    pass

    # 错误的顺序(会报错)
    def func(*args, a, b, **kwargs):
    pass

  • 避免过度使用:如果函数参数数量是固定的,优先使用明确的参数名(如def add(a, b):),而非*args,提升代码可读性。
  • 命名规范:尽量使用*args和**kwargs,而非自定义命名(如*params),符合 Python 社区的编码习惯。
  • 3.2 最佳实践

  • 给*args/**kwargs添加注释,说明预期接收的参数类型和用途;
  • 在函数内部对args/kwargs做参数校验,避免传入无效参数;
  • 结合默认参数使用,平衡灵活性和可读性。
  • 四、总结

    *args和**kwargs是 Python 中提升函数灵活性的核心工具,总结核心要点:

  • *args用于收集任意数量的位置参数,打包成元组;**kwargs用于收集任意数量的关键字参数,打包成字典;
  • 核心使用场景:参数数量不确定、函数封装 / 装饰器、类继承、参数解包;
  • 使用时需注意参数顺序,避免过度使用,优先保证代码可读性。
  • 掌握*args和**kwargs的使用,能让你的 Python 代码更灵活、更健壮,尤其在编写通用工具函数、装饰器等场景下,会成为你的 “得力助手”。希望本文能帮你彻底搞懂这两个知识点,欢迎在评论区交流你的使用心得!

    赞(0)
    未经允许不得转载:171主机测评 » 详解Python中args与*kwargs的使用场景
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址