别再死记硬背了!带你扒开*args和**kwargs的底裤

看到 *args和 **kwargs 这两个东西时一头雾水?不禁脑子里想:这到底是个啥呀,为甚要写它呢?教程都是告诉你怎么用,但就是不告诉你为什么这么用。今天咱们就抛开那些官方辞令,一起扒开它们的底裤,看看里面到底藏着什么秘密!

从两个小烦恼说起

想象一下,你要写一个加法函数。你说:这个简单,哐哐哐一顿输出写出了如下的代码:

python 复制代码
def add(a, b):
    return a + b

后来需求变了,需要三个数相加,你说:这个简单再加一个参数完事儿:

python 复制代码
def add(a, b, c):
    return a + b + c

如果还要支持四个数、五个数相加呢?这时候你就遇到第一个烦恼:参数个数不确定怎么办?

再来看第二个烦恼。假如你要写个用户注册函数呢?:

python 复制代码
def register(name, email, age, address, phone):
    # 注册逻辑
    pass

调用的时候是这样的:

python 复制代码
register("张三", "zhangsan@example.com", 25, "北京市海淀区", "13800138000")

这么多参数,顺序记错了怎么办?参数含义不清晰怎么办?这时候你就需要一种能够明确标识参数含义的方式。

*args:其实就是个打包工

解决第一个烦恼的就是*args。它的本质很简单:就是把多个位置参数打包成一个元组(tuple)

python 复制代码
def add(*numbers):
    print(type(numbers))  # <class 'tuple'>
    total = 0
    for num in numbers:
        total += num
    return total

当你调用add(1, 2, 3, 4)时,Python悄悄做了件事:把1, 2, 3, 4打包成元组(1, 2, 3, 4),然后传给numbers参数。

星号*就像是告诉Python:"帮我把这些零散的位置参数都收集起来,打包成元组!"

这时候你可能会问:为什么非要叫args?叫别的行不行?答案是:完全可以!args只是约定俗成的名字,你写成numbers、params甚至 whatever都行。关键是那个星号,它才是真正的魔法符号。可千万不敢忘了前面那个星号,不然的话,意义就不一样了。说到这里总该明白了吧!

**kwargs:给参数贴上标签

解决第二个烦恼的是**kwargs。它的工作也很明确:把关键字参数打包成一个字典(dict)。

python 复制代码
def register(**user_info):
    print(type(user_info))  # <class 'dict'>
    print(user_info)

调用的时候可以这样:

python 复制代码
register(name="张三", email="zhangsan@example.com", age=25)

Python会把这些关键字参数打包成字典:{"name": "张三", "email": "zhangsan@example.com", "age": 25}

双星号**就像是在说:"把这些带标签的参数都收集起来,打包成字典!"

同样,kwargs也不是必须的,你可以用**info、data等其他名字。关键是双星号

底层原理:参数的解构

其实*和**有两个作用:打包和解包。

打包我们已经说了,就是把多个参数打包成元组或字典。解包则正好相反:

python 复制代码
def show_args(a, b, c):
    print(a, b, c)
    
args = (1, 2, 3)
show_args(*args)  # 相当于 show_args(1, 2, 3)

kwargs = {"a": 1, "b": 2, "c": 3}
show_args(**kwargs)  # 相当于 show_args(a=1, b=2, c=3)

这种解包特性在Python中广泛应用,比如合并列表或字典:

python 复制代码
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = [*list1, *list2]  # [1, 2, 3, 4, 5, 6]

dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = {**dict1, **dict2}  # {"a": 1, "b": 2, "c": 3, "d": 4}

实际应用

知道了原理,我们来看看它们在实际开发中的妙用。

1. 装饰器:不改变函数本身增强功能

装饰器是Python的一大特色,而*args和**kwargs让装饰器能够处理任何函数:

python 复制代码
def log_time(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__}执行时间: {end - start}秒")
        return result
    return wrapper

@log_time
def slow_function():
    time.sleep(1)
    
@log_time
def add(*numbers):
    return sum(numbers)

同一个装饰器,既能装饰无参数的函数,也能装饰有参数的函数。

2. 继承

在面向对象编程中,我们经常需要扩展父类方法:

python 复制代码
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Dog(Animal):
    def __init__(self, breed, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.breed = breed

# 使用
my_dog = Dog(breed="金毛", name="阿黄", age=2)

这样即使Animal类的初始化参数发生变化,Dog类也不需要修改。

3. API设计:灵活处理参数

写第三方库或者框架时,经常需要向下兼容:

python 复制代码
def connect_to_database(host, port=3306, **kwargs):
    # 必需的host参数
    # 可选的port参数
    # 其他可选参数通过kwargs传递
    print(f"连接到 {host}:{port}")
    if 'timeout' in kwargs:
        print(f"超时时间: {kwargs['timeout']}")
    
# 新旧调用方式都支持
connect_to_database("localhost")
connect_to_database("localhost", 3307)
connect_to_database("localhost", timeout=10)
connect_to_database("localhost", 3307, timeout=10, retry=3)

切记切记!!!

虽然*args和**kwargs很强大,但也要注意以下几点:

  • 顺序很重要:在函数定义中,必须是普通参数、*args、**kwargs这个顺序
  • 不要滥用:如果参数明确且固定,直接写明确参数名更清晰

总结

这下总该知道*args和**kwargs了吧!它们只是Python提供的参数打包和解包工具。*args负责处理不确定数量的位置参数,打包成 元组 ;**kwargs负责处理关键字参数,打包成 字典

下次看到*和**,不要再死记硬背了。记住:单星号打包元组,双星号打包字典,反过来就是解包。 就这么简单!

相关推荐
love530love2 小时前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
遇事不決洛必達2 小时前
【Python基础】GIL 锁是什么及其对爬虫的影响
爬虫·python·线程·进程·gil锁
星辰徐哥2 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥2 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约2 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee2 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐2 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs2 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐2 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司2 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录