args,kwargs这两个参数是什么意思?为什么要使用它们?
聊聊 Python 面试题里最常见、也是最容易被面试官拿来压你一头的“*args”和“**kwargs”。别看这俩玩意长得怪,其实用得溜了,简直是写代码的神助攻,尤其是你在搞函数封装、框架开发、装饰器、甚至是设计DSL的时候。
说白了,这俩就是 Python 里的“万能胶”:啥参数都能粘进去,还能优雅地粘得不留痕。
我们先来点干货示例——一个简单的用法:
defdemo(*args, **kwargs):
print("args:", args)
print("kwargs:", kwargs)
demo(1, 2, 3, name='老王', age=18)
输出:
args: (1, 2, 3)
kwargs: {'name': '老王', 'age': 18}
是不是一目了然?*args 拿到的是“所有位置参数”的一个元组,而 **kwargs 拿到的是“所有关键字参数”的一个字典。
那问题来了,这玩意到底有啥用?我不是直接写几个参数更直观吗?
嘿兄弟,这你就太天真了。咱来举几个“踩坑现场”的例子:
场景一:参数太多,改一次函数调用的所有地方都得重写 我以前在一个ERP系统里改一个“生成报表”的接口,因为业务需求变了,要多支持几个过滤条件,结果你猜怎么着?几十处函数调用全都改一遍,简直崩溃。 那时候如果一开始函数设计就用 **kwargs 来接额外参数,新增个过滤项根本不用动主函数的签名。
defgenerate_report(report_type, **filters):
if filters.get('start_date'):
# ...
if filters.get('region'):
# ...
场景二:写装饰器的时候必须用 *args 和 **kwargs 这个是真·必备。你不写这个根本就没法处理带参数的函数。比如你想写个计时器装饰器:
import time
deftimer(func):
defwrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"耗时: {time.time() - start}s")
return result
return wrapper
@timer
defadd(x, y):
time.sleep(1)
return x + y
没有 *args, **kwargs,你根本没法把参数“原样转发”下去,函数就废了。
场景三:函数适配各种第三方框架 比如你写 Django View,或者写 FastAPI 的路径函数,如果你的函数参数写死了,框架调用的时候不匹配就炸;但用了 *args 和 **kwargs,就相当于给你预留了扩展口子。
defmy_view(request, *args, **kwargs):
user_id = kwargs.get('user_id')
# ...
场景四:配置转发 我在写一个命令行工具的时候,把用户输入的配置项转成 dict,然后用 **kwargs 丢进了底层的初始化函数里,完美兼容变化频繁的配置。
defcreate_engine(**db_config):
# 你随便传 host、port、user、password,我都接着
cfg = {'host': 'localhost', 'port': 3306}
create_engine(**cfg)
这在 Flask、Click、Typer 这些框架里用得那叫一个顺溜。
但这俩魔法参数也不是“银弹”,也有坑。
一个经典的坑就是你可能会传入错误参数但还以为没事,结果函数内部根本不识别,悄悄地就默默失败了:
deffoo(**kwargs):
if'timeout'notin kwargs:
print("超时参数缺失")
你传了 timout=10,打错字了,它也不报错,就直接干了……你哭不哭?
所以我一般建议,在函数内部如果你知道你期望哪些关键字参数,最好做个校验,哪怕 raise 一下也比默默吞掉强。
说到这儿,还得扯一句我亲身踩过的坑。
我们团队有个“通用数据导出函数”,接口是这样的:
defexport_data(query_func, format='csv', **options):
...
结果有一次某同事传了 foramt='xls',然后你猜怎么着?系统愉快地返回了一个csv文件……我差点背锅 🙃。后来我们加了个参数白名单,问题才解决。
还有就是 *args 和 **kwargs 混用顺序必须对,否则直接语法错误。记住这个顺序:
deffunc(pos1, pos2, *args, kwonly1=None, **kwargs):
pass
顺序不能错,要不然解释器直接报红。
最后送你一个 Python 高手都喜欢干的骚操作:函数转发时参数透传。
defwrapper(*args, **kwargs):
return real_func(*args, **kwargs)
这个在你搞代理函数、装饰器链、甚至是Monkey Patch时太有用了,写一次就能兼容各种参数组合。
总结一下吧,*args 和 **kwargs,就是 Python 留给开发者最大的自由度之一。你可以不写,但不能不懂。用得好,代码更优雅、接口更通用、扩展更轻松;用得不好,就是 bug 源头。
所以兄弟们,别再被面试官一问就结巴了,下次再有人问你“你知道 *args 和 **kwargs 是干嘛的吗”,你就掏出这篇文章,甩他一脸:不光知道,还用得飞起 😎。
当然,写代码是门艺术,别滥用就好。就像那句话说的,“Python 给了你一把自由的刀,你得知道该怎么用”。
-END-
我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领