hexon
发布于 2025-10-28 / 7 阅读
0

Python中打包和解包操作符全面总结与示例

本文将系统阐述python中 ** 和 * 操作符的使用,列举常用示例。

1. 打包(Packing)操作

1.1 赋值语句中的打包(* → 列表)

# 总是生成列表,即使源是元组
first, *middle, last = 1, 2, 3, 4, 5
print(middle)  # [2, 3, 4] ← 总是列表!

a, *b = (10, 20, 30)
print(b)       # [20, 30] ← 元组源也变成列表!

# 空列表情况
x, *y = [1]
print(y)       # [] ← 空列表

1.2 函数定义中的打包(*args → 元组)

# 总是生成元组,即使传入列表
def func(*args):
    print(f"args类型: {type(args)}, 值: {args}")


func(1, 2, 3)  # args类型: <class 'tuple'>, 值: (1, 2, 3)
func(*[1, 2, 3])  # args类型: <class 'tuple'>, 值: (1, 2, 3)
func([1, 2, 3])  # args类型: <class 'tuple'>, 值: ([1, 2, 3],)

# 这个代码其实左边是合理的写法,但是右边不是合法的python表达式
# *a = *[1, 2, 3]

1.3 函数定义中的打包(**kwargs → 字典)

# 收集关键字参数为字典
def func(**kwargs):
    print(f"kwargs类型: {type(kwargs)}, 值: {kwargs}")


func(a=1, b=2, c=3)  # kwargs类型: <class 'dict'>, 值: {'a': 1, 'b': 2, 'c': 3}

2. 解包(Unpacking)操作

2.1 函数调用中的解包(* → 任何可迭代对象)

def func(a, b, c):
    return a + b + c


# 各种可迭代对象都可以解包
print(func(*[1, 2, 3]))  # 列表 → 6
print(func(*(4, 5, 6)))  # 元组 → 15
print(func(*"789"))  # 字符串 → '789'(字符连接)
print(func(*range(3)))  # range对象 → 0+1+2 → 3

# 解包生成器
gen = (x for x in [10, 20, 30])
print(func(*gen))  # 60

2.2 函数调用中的解包(** → 仅字典,键必须是字符串)

def func(name, age, city):
    return f"{name} is {age} years old, lives in {city}"


# 字典解包为关键字参数
person = {"name": "Alice", "age": 25, "city": "Beijing"}
print(func(**person))  # Alice is 25 years old, lives in Beijing

# 键必须是字符串!
bad_dict = {1: 'Alice', 2: 25}  # 不能解包,键不是字符串
# print(func(**bad_dict))  # TypeError: keywords must be strings

2.3 赋值语句中的解包(自动解包)

# 不需要显式使用 *
a, b, c = [1, 2, 3]  # 自动解包
print(a, b, c)  # 1 2 3

x, y, z = (4, 5, 6)  # 元组自动解包
print(x, y, z)  # 4 5 6

3. 混合使用场景

3.1 函数定义中的混合使用

def complex_func(a, b, *args, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args={args} (类型: {type(args)})")
    print(f"kwargs={kwargs} (类型: {type(kwargs)})")


complex_func(1, 2, 3, 4, 5, x=10, y=20)
# 输出:
# a=1, b=2
# args=(3, 4, 5) (类型: <class 'tuple'>)
# kwargs={'x': 10, 'y': 20} (类型: <class 'dict'>)

3.2 字典合并(Python 3.5+)

# 使用 ** 解包字典进行合并
dict1 = {"a": 1, "b": 2}
dict2 = {"c": 3, "d": 4}
merged = {**dict1, **dict2}
print(merged)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

# 后面的字典覆盖前面的键
dict3 = {"a": 100, "e": 5}
merged2 = {**dict1, **dict3}
print(merged2)  # {'a': 100, 'b': 2, 'e': 5}

3.3 列表/元组合并

# 使用 * 解包可迭代对象进行合并
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined_list = [*list1, *list2]
print(combined_list)  # [1, 2, 3, 4, 5, 6]

combined_tuple = (*list1, *list2)
print(combined_tuple)  # (1, 2, 3, 4, 5, 6)

4. 特殊注意事项

4.1 语法限制

# ❌ 错误:赋值右边不能单独使用 *
lst = [1, 2, 3]
# a, b, c = * lst  # SyntaxError

# ✅ 正确:需要形成完整表达式
a, b, c = *lst,    # 注意逗号,创建元组
a, b, c = lst      # 直接解包(推荐)

4.2 只能使用在赋值或函数参数中

# ❌ 这些会报错
# result = *[1, 2, 3]           # SyntaxError
# if *[True, False]: pass       # SyntaxError

# ✅ 这些是允许的
result = [*[1, 2, 3]]          # 在列表内解包
args = (*[1, 2, 3],)           # 在元组内解包

5. 实用技巧

5.1 提取文件路径各部分

path = "/home/user/documents/file.txt"
*folders, filename = path.split("/")
print(folders)  # ['', 'home', 'user', 'documents']
print(filename)  # file.txt

5.2 处理不确定数量的返回值

def get_data():
    return "success", {"data": [1, 2, 3]}, 200, "extra", "info"


status, data, code, *extras = get_data()
print(status)  # success
print(extras)  # ['extra', 'info']

5.3 灵活的API包装器

def api_wrapper(endpoint, *args, **kwargs):
    # 记录日志
    print(f"调用 {endpoint},参数: {args},关键字参数: {kwargs}")
    # 实际API调用(模拟)
    return f"结果来自 {endpoint}"


# 可以接受任意参数
result1 = api_wrapper("/users", 1, 2, 3, fields="name,age")
result2 = api_wrapper("/posts", category="tech", limit=10)

总结表格

场景

语法

结果类型

限制

赋值打包

*变量

列表

只能用在赋值左边

函数定义打包

*args

元组

只能用在函数参数

函数定义打包

**kwargs

字典

只能用在函数参数,键为字符串

函数调用解包

*iterable

展开元素

任何可迭代对象

函数调用解包

**dict

关键字参数

仅字典,键为字符串

赋值解包

自动

多个变量

右边直接放可迭代对象