深入明确Python中的邪术参数 *args 和 **kwargs

[复制链接]
发表于 2026-1-22 22:03:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在Python编程中,函数的机动性是其强大之处之一。此中,*args 和 **kwargs 是实现函数参数可变性的紧张工具。

无论我们是Python初学者照旧履历丰富的开发者,充实明确这两个概念都有助于编写更加机动、高效的代码。
本文将深入探究*args和**kwargs的用法、原理和应用场景,以全面把握它们。
一、初识 *args 和 **kwargs

*args 和 **kwargs 都是python中的可变参数。
*args可以用来表现任何多个无名参数,本质上是元组范例。
**kwargs可以用来表现关键字参数,本质上是字范例例。

1. 什么是 *args?

*args 答应函数继承恣意数目标位置参数,这些参数会以元组的情势传入函数内部。
args是“arguments”(参数)的缩写,但名称并非固定,关键在于星号*。
示例:
  1. def sum_numbers(*args):
  2.     total = 0
  3.     for number in args:
  4.         total += number
  5.     return total
  6. print(sum_numbers(1, 2, 3))  # 输出:6
复制代码
2. 什么是 **kwargs?

**kwargs 答应函数继承恣意数目标关键字参数,这些参数会以字典的情势传入函数内部。
kwargs是“keyword arguments”(关键字参数)的缩写,同样,名称不固定,关键在于双星号**。
示例:
  1. def greet(**kwargs):
  2.     for key, value in kwargs.items():
  3.         print(f"{key} = {value}")
  4. greet(name='Alice', age=30)
  5. # 输出:
  6. # name = Alice
  7. # age = 30
复制代码
二、深入明确 *args

1. 使用场景

参数数目未知:当您界说的函数必要继承不定命量的位置参数时,*args非常有用。
函数包装器:在编写装饰器或高阶函数时,必要通报参数给被装饰函数。
2. 工作原理

当函数界说中包罗*args时,传入的全部位置参数都会被网络到一个元组中,您可以像处置处罚元组一样处置处罚args。
示例:
  1. def display_args(first_arg, *args):
  2.     print("第一个参数:", first_arg)
  3.     print("其他参数:", args)
  4. display_args(10, 20, 30, 40)
  5. # 输出:
  6. # 第一个参数: 10
  7. # 其他参数: (20, 30, 40)
复制代码
3. 注意事项

*args必须放在函数界说参数列表的末了,除非尚有**kwargs。
在调用函数时,不能使用关键字参数通报给*args。
三、深入明确 **kwargs

1. 使用场景

参数名未知:当函数必要继承恣意数目标关键字参数,且参数名在界说时未知。
设置参数:处置处罚设置项或可选参数。
2. 工作原理

函数界说中包罗**kwargs时,全部的关键字参数都会被网络到一个字典中,您可以像处置处罚字典一样处置处罚kwargs。
示例:
  1. def display_kwargs(**kwargs):
  2.     for key, value in kwargs.items():
  3.         print(f"{key} : {value}")
  4. display_kwargs(name='祖冲之', age=25, country='China')
  5. # 输出:
  6. # name : 祖冲之
  7. # age : 25
  8. # country : China
复制代码
3. 注意事项

**kwargs必须放在函数界说参数列表的末了。
在函数调用时,关键字参数的名称必须是有用的Python标识符。
四、同时使用 *args 和 **kwargs

1. 函数界说次序

在函数界说中,参数的次序必须为:

  • 位置参数(必须参数)
  • 默认参数(可选参数)
  • *args(可变位置参数)
  • **kwargs(可变关键字参数)
示例:
  1. def func(a, b=2, *args, **kwargs):
  2.     print("a =", a)
  3.     print("b =", b)
  4.     print("args =", args)
  5.     print("kwargs =", kwargs)
  6. func(1, 3, 5, 7, x=10, y=20)
  7. # 输出:
  8. # a = 1
  9. # b = 3
  10. # args = (5, 7)
  11. # kwargs = {'x': 10, 'y': 20}
复制代码
2. 应用场景

最大化函数的机动性:答应函数继承恣意范例和数目标参数。
编写通用代码:如装饰器、日志日志纪录器等,必要处置处罚差别的函数署名。
五、参数解包与通报

1. 位置参数的解包(*)

将序列(如列表、元组)中的元素解包为单独的参数通报给函数。
示例:
  1. def add(a, b, c):
  2.     return a + b + c
  3. numbers = [1, 2, 3]
  4. result = add(*numbers)  # 等价于 add(1, 2, 3)
  5. print(result)  # 输出:6
复制代码
2. 关键字参数的解包(**)

将字典中的键值对解包为关键字参数通报给函数。
示例:
  1. def introduce(name, age, country):
  2.     print(f"我叫{name},今年{age}岁,来自{country}。")
  3. info = {'name': 'Charlie', 'age': 28, 'country': 'China'}
  4. introduce(**info)
  5. # 输出:我叫Charlie,今年28岁,来自China。
复制代码
3. 同时解包

示例:
  1. def func(a, b, c, d):
  2.     print(a, b, c, d)
  3. args = (1, 2)
  4. kwargs = {'c': 3, 'd': 4}
  5. func(*args, **kwargs)
  6. # 输出:1 2 3 4
复制代码
六、在装饰器中的应用

1. 为什么在装饰器中使用?

装饰器必要可以大概装饰恣意函数,无论其参数怎样界说。
使用*args和**kwargs,可以编写一个通用的装饰器,实用于全部函数。
2. 编写通用装饰器

示例:
  1. def logger(fn):
  2.     def wrapper(*args, **kwargs):
  3.         print(f"正在调用函数 {fn.__name__},参数:args={args}, kwargs={kwargs}")
  4.         result = fn(*args, **kwargs)
  5.         print(f"函数 {fn.__name__} 调用完毕,返回值:{result}")
  6.         return result
  7.     return wrapper
  8. @logger
  9. def multiply(a, b):
  10.     return a * b
  11. @logger
  12. def greet(name, message='Hello'):
  13.     return f"{message}, {name}!"
  14. multiply(3, 4)
  15. # 输出:
  16. # 正在调用函数 multiply,参数:args=(3, 4), kwargs={}
  17. # 函数 multiply 调用完毕,返回值:12
  18. greet(name='Alice')
  19. # 输出:
  20. # 正在调用函数 greet,参数:args=(), kwargs={'name': 'Alice'}
  21. # 函数 greet 调用完毕,返回值:Hello, Alice!
复制代码
3. 深入明确

*args和**kwargs的通报:装饰器内部的wrapper函数继承*args和**kwargs,并将其通报给被装饰的函数fn。
保持函数署名:如许,装饰器不会改变原函数的参数要求。
七、现实应用案例

1. 参数校验

使用*args和**kwargs,可以编写装饰器来查抄参数的范例或值。
示例:
  1. def type_check(fn):
  2.     def wrapper(*args, **kwargs):
  3.         for arg in args:
  4.             if not isinstance(arg, int):
  5.                 raise TypeError("所有参数必须是整数")
  6.         return fn(*args, **kwargs)
  7.     return wrapper
  8. @type_check
  9. def add_integers(*args):
  10.     return sum(args)
  11. print(add_integers(1, 2, 3))  # 输出:6
  12. # add_integers(1, '2', 3)  # 抛出 TypeError: 所有参数必须是整数
复制代码
2. 缓存函数效果(Memoization)

示例:
  1. def memoize(fn):
  2.     cache = {}
  3.     def wrapper(*args):
  4.         if args in cache:
  5.             return cache[args]
  6.         result = fn(*args)
  7.         cache[args] = result
  8.         return result
  9.     return wrapper
  10. @memoize
  11. def fibonacci(n):
  12.     if n <= 2:
  13.         return 1
  14.     return fibonacci(n-1) + fibonacci(n-2)
  15. print(fibonacci(10))  # 输出:55
复制代码
3. 同一接口的API筹划

筹划可继承各种参数的API,进步机动性。
示例:
  1. def api_request(endpoint, *args, **kwargs):
  2.     url = f"https://api.example.com/{endpoint}"
  3.     print(f"请求URL:{url}")
  4.     print(f"位置参数:{args}")
  5.     print(f"关键字参数:{kwargs}")
  6.     # 这里可以添加实际的请求逻辑
  7. api_request('get-data', 1, 2, key='value', token='abcd1234')
  8. # 输出:
  9. # 请求URL:https://api.example.com/get-data
  10. # 位置参数:(1, 2)
  11. # 关键字参数:{'key': 'value', 'token': 'abcd1234'}
复制代码
八、总结

机动性: *args和**kwargs使函数可以大概继承可变数目和范例的参数,增长了函数的机动性。
代码复用: 在装饰器和高阶函数中使用,能编写更加通用的代码。
注意事项: 使用时要注意参数的次序息争包的精确性,制止参数辩论。
通过深入明确和机动运用*args和**kwargs,我们可以编写出更加高效、机动的Python代码。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表