page contents

Python 程序员必修课:为什么说 *args 和 **kwargs 是“万能接口”?

你有没有遇到过这种场景:写了一个函数,参数死板得像石头,非得按照顺序一个个传。如果临时想多加几个参数,立马报错。于是你只能不停改函数定义,改着改着自己都乱了。

attachments-2025-08-uu2TgY6068a527086c06e.jpg你有没有遇到过这种场景:写了一个函数,参数死板得像石头,非得按照顺序一个个传。如果临时想多加几个参数,立马报错。于是你只能不停改函数定义,改着改着自己都乱了。

其实 Python 早就给了我们一个神器,专门解决这种“参数不确定”的尴尬场景——那就是 *args 和 **kwargs。别被这两个名字吓到,它们的本质其实就是两个袋子:

一个袋子专门装位置参数(*args → 元组);另一个袋子专门装关键字参数(**kwargs → 字典)。只要学会用这两个袋子,你的函数立刻灵活到飞起。

1. 最直观的感受:把参数全都装起来

我们先看个最常见的例子:

def demo_args(a, b, *args, **kwargs):

    print(f"标准参数: {a}, {b}")

    print(f"位置参数 (*args): {args} (类型: {type(args)})")

    print(f"关键字参数 (**kwargs): {kwargs} (类型: {type(kwargs)})")

demo_args(1, 2, 3, 4, 5, name="Alice", age=30)

输出结果一目了然:

前两个是标准参数;

额外的数字自动打包进 args,形成一个元组;

关键字参数则全都放进 kwargs,成了字典。

是不是很像餐厅点菜?前两个是必点菜,剩下的都扔进大盘子里,不用提前规定数量。

2. 为什么说它是“解放双手”的神器?

来想象一个真实的场景:你写了一个计算器函数,有时候只想加法,有时候要算平均值,有时候还要控制小数点精度。如果不用 *args 和 **kwargs,你得写一堆重复函数。

看看这个版本:

def safe_calculator(op, *nums, **options):

    # 验证数字类型

    if not all(isinstance(n, (int, float)) for n in nums):

        raise TypeError("必须输入数字")

    # 处理选项

    precision = options.pop('precision', 2)  # 默认精度2

    if options:  # 检查未处理的关键字

        raise ValueError(f"无效选项: {', '.join(options.keys())}")

    # 执行操作

    if op == 'add':

        result = sum(nums)

    elif op == 'avg':

        result = sum(nums) / len(nums)

    else:

        raise ValueError("未知操作")

    return round(result, precision)

print(safe_calculator('avg', 1.5, 2, 3.7, precision=3))  # 2.400

注意几个亮点:

位置参数随便丢几个数字进去就能算;

精度控制这种额外需求,直接扔进 kwargs;

未来如果想扩展新功能,直接加关键字参数即可,完全不用改函数结构。

这就是 *args 和 **kwargs 的精髓:让函数保持开放扩展,而不是死板固定。

3. 代码复用的幕后英雄:装饰器和继承

很多人刚学 Python,觉得装饰器、继承这些高阶语法晦涩难懂。但只要你知道 *args 和 **kwargs,其实它们背后就是在做参数打包和转发。

(1)装饰器的例子

def debug_decorator(func):

    def wrapper(*args, **kwargs):

        print(f"调用函数: {func.__name__}({args}, {kwargs})")

        result = func(*args, **kwargs)

        print(f"返回结果: {result}")

        return result

    return wrapper

@debug_decorator

def multiply(a, b):

    return a * b

multiply(5, b=6)

这里的 wrapper 就像一个“万能接口”,不管传什么参数,它都能兜住,再原封不动转给真正的函数。这就是为什么装饰器能无缝给任何函数加功能。

(2)继承的例子

class Animal:

    def __init__(self, name, legs):

        self.name = name

        self.legs = legs


class Bird(Animal):

    def __init__(self, can_fly, *args, **kwargs):

        super().__init__(*args, **kwargs)  # 透传参数

        self.can_fly = can_fly

parrot = Bird(can_fly=True, name="Polly", legs=2)

print(f"{parrot.name} 有 {parrot.legs} 条腿, 会飞: {parrot.can_fly}")

如果不用 *args 和 **kwargs,你就得在子类里重复写一堆父类的参数传递逻辑。现在只要透传一下,父类需要啥,它自动帮你装好送过去。这就是优雅。

4. 容易踩的坑:这几个错误一定要避开

别看 *args 和 **kwargs 灵活,但也有一些“暗礁”,很多人第一次都会踩。

参数顺序不能乱正确顺序是:标准参数 → *args → 关键字参数 → **kwargs。 否则报错让你怀疑人生。

别重复赋值

def problematic(x, **kwargs):

    print(x, kwargs)

problematic(1, x=2)  # 报错:x重复赋值

调用时顺序要对位置参数要放前面,关键字参数在后面,不然会直接 SyntaxError。

5. 实用小技巧:写代码更优雅

强制关键字参数

def safe_divide(numerator, denominator, *, ignore_zero=False):

    if denominator == 0:

        return float('inf') if ignore_zero else None

    return numerator / denominator

print(safe_divide(5, 0))  # None

print(safe_divide(5, 0, ignore_zero=True))  # inf

加一个 *,后面参数必须写成关键字形式,避免调用时传错位置。

字典合并

def merge_config(defaults, **overrides):

    return {**defaults, **overrides}


config = merge_config({"color": "red", "size": 10}, size=20, opacity=0.5)

# {'color': 'red', 'size': 20, 'opacity': 0.5}

API 参数转发

class Database:

    def execute(self, query, *params, **options):

        print(f"执行查询: {query}")

        print(f"参数: {params}")

        print(f"选项: {options}")


class UserService:

    def __init__(self, db):

        self.db = db

    

    def get_user(self, user_id, use_cache=True):

        return self.db.execute(

            "SELECT * FROM users WHERE id = %s",

            user_id,

            timeout=10,

            cache=use_cache

        )

db = Database()

service = UserService(db)

service.get_user(123, use_cache=False)

看到了吗?转发参数就像“物流分拣中心”,原封不动把数据派送给下一层。

6. 总结:*args 和 **kwargs 就是 Python 的“保险丝”

很多人写 Python 程序时,最怕的就是“未来需求变了”。今天只要两个参数,明天可能要十个。你不能每次都把函数拆了重写,这样太费劲。

而 *args 和 **kwargs,正是 Python 设计给你的灵活接口:

*args → 位置参数打包成元组;

**kwargs → 关键字参数打包成字典;

它们能让函数写得既简洁,又能轻松扩展;

常见应用:装饰器、继承、参数校验、API设计……

记住一句话:**当你不确定未来会传什么参数时,就放心交给 *args 和 kwargs。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2025-08-20 09:38
  • 阅读 ( 21 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
小柒
小柒

2172 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2172 文章
  3. Pack 1335 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章