【小白笔记】在 Python 中,*args、**kwargs 和 zip
·
在 Python 中,*args、**kwargs 和 zip 是编写灵活、简洁代码的三个核心工具。我们可以把它们拆解开来看。
1. *args 和 **kwargs:可变参数
这两个语法允许你向函数传递不确定数量的参数。
*args (Non-keyword Arguments)
- 本质: 这里的
*是关键,它告诉 Python 将所有传入的位置参数打包成一个元组(Tuple)。 - 用途: 当你不确定用户会传多少个参数时使用。
- 示例:
def sum_numbers(*args):
return sum(args) # args 在这里是一个元组,比如 (1, 2, 3)
print(sum_numbers(1, 2, 3, 4)) # 结果为 10
**kwargs (Keyword Arguments)
- 本质: 这里的
**告诉 Python 将所有传入的关键字参数(即key=value形式)打包成一个字典(Dictionary)。 - 用途: 用于处理带有名称的参数。
- 示例:
def show_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
show_info(name="Alice", age=25) # kwargs 是 {'name': 'Alice', 'age': 25}
注意:
args和kwargs只是约定俗成的命名,你写成*vars或**params也可以,但为了代码可读性,建议遵循标准。
2. zip 是什么?
zip() 函数像拉链一样,将多个可迭代对象(列表、元组等)对应的元素打包在一起。
- 工作原理: 它取第一个列表的第 1 个元素和第二个列表的第 1 个元素配对,以此类推。
- 示例:
names = ["Alice", "Bob"]
scores = [85, 92]
zipped = zip(names, scores)
print(list(zipped)) # 结果: [('Alice', 85), ('Bob', 92)]
3. 为什么是元组(Tuple)?
你可能会问:为什么 *args 打包出来的是元组,而不是列表?为什么 zip 内部生成的每一对也是元组?
主要有以下三个原因:
- 不可变性(Immutable): 元组一旦创建就不能修改。在函数调用时,参数通常是不希望被意外修改的。使用元组可以保证数据的安全性。
- 性能(Performance): 元组比列表更轻量,占用的内存更少,创建和遍历的速度也略快。对于频繁的函数调用,这能提升效率。
- 语义化:
- 列表通常用于存储“同质”的数据(比如一串待处理的用户 ID)。
- 元组通常用于存储“异质”但有结构的数据(比如一个人的姓名和年龄配对)。
args和zip的结果更符合这种结构化的语义。
总结对比
| 概念 | 语法 | 结果类型 | 主要用途 |
|---|---|---|---|
*args |
* |
元组 | 接收任意数量的位置参数 |
**kwargs |
** |
字典 | 接收任意数量的关键字参数 |
zip |
zip(a, b) |
迭代器 (含元组) | 将多个序列配对合并 |
既然你提到了解包(Unpacking),这其实是 * 最迷人的地方。如果说在函数定义时 * 是“打包”,那么在函数调用时,它就是“拆箱”。
你可以把 * 想象成一个**“拆包器”**,它能把容器里的物件一个个拿出来摆好。
1. 在函数调用时解包
当你有一个列表或元组,但函数需要的是一个个独立的参数时,* 就派上用场了。
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
# 正常调用:add(nums[0], nums[1], nums[2])
# 使用解包:
print(add(*nums)) # 相当于执行 add(1, 2, 3)
同样地,** 专门用于解包字典,将其转换为关键字参数:
def greet(name, age):
print(f"Hello {name}, you are {age} years old.")
user_info = {"name": "Alice", "age": 25}
greet(**user_info) # 相当于执行 greet(name="Alice", age=25)
2. 在赋值时解包(进阶用法)
除了函数调用,* 还能帮你灵活地处理变量赋值。这在处理不确定长度的列表时非常高效。
# 提取开头、结尾和中间所有内容
first, *middle, last = [1, 2, 3, 4, 5, 6]
print(first) # 1
print(middle) # [2, 3, 4, 5] (注意:解包出来的中间部分是列表)
print(last) # 6
3. 合并容器
在 Python 3.5+ 中,解包还可以用来优雅地合并列表或字典:
- 合并列表:
list_a = [1, 2]
list_b = [3, 4]
combined = [*list_a, *list_b] # [1, 2, 3, 4]
- 合并字典:
dict_a = {"x": 1}
dict_b = {"y": 2}
merged = {**dict_a, **dict_b} # {'x': 1, 'y': 2}
为什么这种设计很聪明?
- 代码更干净:不需要写繁琐的循环或索引(如
data[0],data[1])。 - 接口兼容性:如果你有一个现成的配置字典,可以直接通过
**config传给函数,而不需要一个个手动提取键值。 - 极度灵活:它让函数能够处理各种形状的数据输入。
一个有趣的小挑战
如果你运行 print(*"Hello"),你觉得输出会是什么?
答案: 会输出
H e l l o。因为字符串也是可迭代对象,*会把它拆成一个个独立的字符传给
更多推荐
所有评论(0)