Python中的zip(), *zip()与zip(*zip(a,b))

作为一个Python初学者,昨天在实践书上一个实例时遇到了zip()和*zip()函数,而书中恰好对这两个函数没有过多的解释(这两个函数其实是同一个函数),网上搜索后对zip()倒是弄明白了,但是对*zip()的说法,CSDN上大部分人却是说其是zip()的逆操作云云,但是操作下来感觉完全不是一回事,后来又搜了几个不同的文章,结合自己的代码操作后才完全把这个事情弄明白,所以将其记录下来,方便自己的同时也看看能不能帮助到同样有疑惑的Python初学者们。


首先说结论:

1. zip()和*zip()是同一个函数,而非后者是前者的逆操作,两者操作结果不同的原因主要是因为星号*的存在
2. 通俗的说,倒不如说zip()是压缩操作,而*星号是解压缩操作,* 才是zip()的逆操作


下面简述zip()函数并用coding来说明我的结论:

Zip():

作用:压缩数组,把多个列表压缩成多个多元元素(ps.这里的几元元素指的是一个元素里有几个值,如果我的说法不准确或者错用了名词,欢迎大家指正我)

特性:

1. 当操作数之间长度不一致时,其长度与最短操作数的长度一致

a = [1,2,3] 
b = [4,5,6,7] 
c = [4,5,6,7,8]  
zipped = zip(a,b,c) 

print(*zipped) = (1, 4, 4) (2, 5, 5) (3, 6, 6)
a, b, c的长度分别为3,4,5,最后zipped的长度为3,把三个列表压缩成了3个三元元素,(为什么这里输出时要加个*号呢,请大家往下看)

2. 在python3中,zip()函数返回的值是一个迭代器,这个迭代器表示的是数据存储在内存中的哪个位置,而不能直接进行访问/输出/使用,需要用list,for循环或者*号解压后才能正常显示。

print(zipped)
print(list(zipped))
print(*list(zipped))
#输出分别为
<zip object at 0x014C22E8>
[(1, 4, 4), (2, 5, 5), (3, 6, 6)] 
(1, 4, 4) (2, 5, 5) (3, 6, 6)
此时我们分别对比输出结果,反应快的朋友可能已经发现了,*号的存在使得输出结果“少了一层”,从一个由“三个元组组成的列表”变成了“三个元组”(ps.元组就是组内元素不可改变的列表)。
所以也可以说,*号让一个二维列表变成了多个一维元组。所以当我简单的print(*zipped)时,星号的作用是把zipped的“迭代器”格式解了一层,把它变成了可以打印出来的“数据格式”,接下来我会在下面用coding再次简述一下*号。

注意:有时候你可能会发现,你输出完zipped后,想再次输出时,列表里为空了。这是因为,zip()在python3中返回一个迭代器,你只能在迭代器迭代一次,用完后元素虽然不会消失,但再次迭代会得到0个元素,除zip外,map,filter也是如此,因为python就是这么规定的。


*号的特性:对操作数进行“解压“

a = 5
b = [3,4,5]
c = [(3,4,5), (6,7,8)]
d = [[(3,4,5),(6,7,8)]]
---
print(*a)  #结果会出现error
print(*b)
print(*c)
print(*d)
#输出分别为
Error
3 4 5
(3, 4, 5) (6, 7, 8)
[(3, 4, 5), (6, 7, 8)]
可以发现,*号把所有操作数都解压了一层,二维列表变成了一维,三维变成了二维,而对int进行解压报错时,错误提示为

print() argument after * must be an iterable, not int
*号后必须为迭代器,而不能是int类型的值

可以简单理解为int已经是“数据基础格式”了,不能再进行解压缩了

简述完zip()和*号,接下来就是最后的zip(*zip(a,b))及利用zip进行矩阵运算。
很多人说*zip()是zip()的逆操作,但是当他们展示code时,却往往写的是zip(*zip(a,b))(CSDN上超过一半的人对zip(), *zip()都是这样说的,直至我搜关于*星号的文章后才恍然大悟)按照这个逻辑,其实应该是*zip(zip(a,b))才对,因为根据函数嵌套,总是先运行括号内的,zip(*zip(a,b))不就变成“先解压缩再进行压缩”了?
然而,*zip(zip(a,b))后,输出的结果并不是预想中的结果,反而m,n = zip(*zip(a,b))输出的结果才是原来的结果,这是为什么呢?

1. *zip(zip(a,b))

首先说一下,当zip后只有一个列表时,他会进行迭代操作,把这个列表和元素为0的空列表进行迭代,所以当zip的操作数只有一个时,程序并不会报错。
a = [1,2,3]
zipped = zip(a) 
print(list(zipped)) = [(1,), (2,), (3,)]
a = [1,2,3]
b = [4,5,6,7]
zipped = zip(a,b)     #此时zipped中数据为(1,4) (2,5) (3,6)
zippeded = zip(zipped)  #再调用一次zip
print(*zippeded) = ((1, 4),) ((2, 5),) ((3, 6),)    #简直和原来的a,b大相径庭

2. m,n = zip(*zip(a,b))

m = [1, 2, 3]
n = [4, 5, 6]

print("zip(m, n)返回:", list(zip(m, n)))
print("*zip(m, n)返回:", *zip(m, n))
m2, n2 = zip(*zip(m, n))
print("m2和n2的值分别为:", m2, n2)
#输出结果为
zip(m, n)返回: [(1, 4), (2, 5), (3, 6)]
*zip(m, n)返回: (1, 4) (2, 5) (3, 6)
m2和n2的值分别为: (1, 2, 3) (4, 5, 6)
虽然括号不一样了,从一开始的[ ]变成了后面的( ),但是既然元组是元素不可变的列表,两者的值其实都是一样的,进一步拆解一下:
#因为*zip(m,n)返回值为(1,4) (2,5) (3,6),此时再对其zip一遍,是不是等效于下面的代码了
_1 = (1,4)
_2 = (2,5)
_3 = (3,6)
m1,m2 = zip(_1,_2,_3)    #分别把结果的2个元素赋给m1和m2,所以又还原成了(1,2,3) (4,5,6)
所以,并不是*zip()是逆操作,而是又进行了一次zip()操作,把列表转置回来了。
因此,zip()也可用于进行矩阵运算,当你进行一次zip时,横坐标和纵坐标调换了一次,这在矩阵乘法中很常见,而使用2次zip操作,则又把横纵坐标调换回来了,或许这也是各位CSDN作者只从结果看,又看到zip()和*zip()这两个看起来如此对仗的操作,便把两者当成互逆操作的原因吧,其实*在其中的作用只是解压了第一次zip后的迭代器格式,把其转换成数据格式罢了。
带*号变量严格来说并不是一个变量,在解压后,它其实是一个参数,一个数据,它不能作为一个变量而被赋值,但可以作为参数传递。正如你不能对int数1,2,3,4,5赋值一样

洋洋洒洒写了不少,希望能帮助到大家,如果我的文章中有什么错误或者不准确的地方,也欢迎大家勘误,大家共同学习。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342