Python技术迷

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 全部免费领