python中的封包解包与zip函数


原文地址: https://zhuanlan.zhihu.com/p/702419094

Packing 封包

所谓封包指的是,将多个值赋值给一个变量时,Python 会自动将这些值封包为一个元组

>>> count = 996, 123, -3
>>> count
(996, 123, -3)

Unpacking 解包

序列 / 可迭代对象解包

  1. 所谓 序列 / 可迭代对象解包 指的是:对一个序列(或可迭代对象)解包,并将得到的值存储到一系列变量中。
>>> name1, name2, name3 = ["Tom","Aaron","Bob"]
>>> print(f"{name1 = }")
>>> print(f"{name2 = }")
>>> print(f"{name3 = }")
name1 = 'Tom' 
name2 = 'Aaron'
name3 = 'Bob'
  1. 解包的序列 (或可迭代对象) 包含的元素个数必须与等号左侧的变量数相同,否则会抛异常。
# ——————————————————————input——————————————————————

students = {"Bob", "Aaron", "tony"}
try:
    s1, s2 = students
except Exception as ex:
    print("ex:",ex)
    
try:
    s1, s2, s3, s4 = students
except Exception as ex:
    print("ex:",ex)

# ——————————————————————output——————————————————————
ex = ValueError('too many values to unpack (expected 2)') 
ex = ValueError('not enough values to unpack (expected 4, got 3)')
  1. 如果解包的序列 (或可迭代对象) 包含的元素个数与等号左侧的变量数不同时,可在变量名前添加 * 星号,其会将多余的值以列表的形式赋值给该变量。
    显然存在多个 * 星号变量会报错
>>> a, *b, c = (11, 22, 33, 44, 55, 66)
>>> print(f"{a = }")
>>> print(f"{b = }")
>>> print(f"{c = }")
a = 11 
b = [22, 33, 44, 55]
c = 66
  1. 解包时如果不关心该位置的值, 可以使用占位符_下划线
>>> f, _, g, _ = (11, 22, 33, 44)
>>> print(f"{f = }")
>>> print(f"{g = }")
f = 11 
g = 33
  1. 需要注意的是,进行解包时,左侧不能只有一个变量名(ps.这不废话么… 一个变量名还叫啥解包…这不就是直接赋值吗…😅)
>>> x = (11, 22, 33)
>>> print(f"{x = }")
x = (11, 22, 33)

# 此时,可以通过*_来实现
>>> y, *_ = (11, 22, 33)
>>> print(f"{y = }")
y = 11

解包传参

  • 对于 序列对象,在实参添加 * 前缀,其会将序列对象解包为若干个元素,作为函数调用的位置实参
  • 对于 字典对象,在实参添加 ** 前缀, 其会将字典解包为若干个键值对,作为函数调用的关键字实参
# ——————————————————————input——————————————————————
def fun(a,b,/,c,d,*args, x,y,z,**kw):
    print("a:",a,"b:",b,"c:",c,"d:",d)
    print("args:", args)
    print("x:",x,"y:",y,"z:",z)
    print("kw:", kw)

list1 = [0,1,2,3,4]
dict1 = {"x":5,"y":6,"z":7,"u":8,"v":9}

fun(*list1, **dict1)

# ——————————————————————output——————————————————————
a: 0 b: 1 c: 2 d: 3
args: (4,)
x: 5 y: 6 z: 7
kw: {'u': 8, 'v': 9}

交换变量

在其他语言中交换变量值,通常需要依赖中间变量来实现。但在 Python 中却可以直接交换。其中对于多变量交换时,其底层实现原理即是通过序列解包实现的

>>> a, b, c, d = 1, 2, 3, 4
>>> a, b, c, d = b, d, a, c
>>> print(f"{a = }")
>>> print(f"{b = }")
>>> print(f"{c = }")
>>> print(f"{d = }")
a = 2
b = 4
c = 1
d = 3

zip 函数

  1. zip 函数将可迭代对象作为参数,其会把各可迭代对象中对应位置的元素打包为一个元组。可将 zip 结果对象转换为 list 来查看、遍历。需要注意的是,当各可迭代对象的长度不同时,zip 函数将在长度最短的可迭代对象用完时,停止打包
# ——————————————————————input——————————————————————
names = ["Aaron", "Tom", "Bob", "Tony"]
ages = (18, 33, 72)
sexs = ["man", "male", "woman", "null"]

zip_result = zip(names, ages, sexs)
zip_list = list(zip_result)

print(f"{zip_result = }")
print(f"{zip_list = }")

# ——————————————————————input——————————————————————
zip_result = <zip object at 0x00000234AC4A1900>
zip_list = [('Aaron', 18, 'man'), ('Tom', 33, 'male'), ('Bob', 72, 'woman')]
  1. 对 zip 对象解包时,可在传递实参 zip 结果对象的前添加 * 前缀

[!important] zip 返回迭代器!!!
迭代器只能遍历一次!!!
如果对 zip 结果输出遍历过一次,比如将其转换为了 list,则原本的 zip 结果就不能再进行遍历了,也就不能再进行 zip(*) 解包操作了,但是此时可以对转换得到的 list 进行解包。

# ——————————————————————input——————————————————————
names = ["Aaron", "Tom", "Bob", "Tony"]
ages = (18, 33, 72)
sexs = ["man", "male", "woman", "null"]
zip_result = zip(names, ages, sexs)
zip_list = list(zip_result)
# 注意,zip_result在转换为list时已经迭代了一次了,所以无法再次迭代解包了
# my_name, my_age, my_sex = zip(*zip_result)
# 但是list可以多次迭代解包
my_name, my_age, my_sex = zip(*zip_list)
print(f"my_name : {my_name}")
print(f"my_age : {my_age}")
print(f"my_sex : {my_sex}")

# ——————————————————————output——————————————————————
my_name : ('Aaron', 'Tom', 'Bob')
my_age : (18, 33, 72)
my_sex : ('man', 'male', 'woman')

参考文献

  1. Python 编程 · 第 3 版:从入门到实践 Eric Matthes 著
  2. Python 基础教程 · 第 3 版 Magnus Lie Hetland 著
  3. 流畅的 Python· 第 1 版 Luciano Ramalho 著
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值