通过拆解
[list(row) for row in zip(*matrix)]这行代码,彻底搞懂 Python 中zip()函数与*解包操作符的底层逻辑,培养 Pythonic 的编程思维。
在 Python 的日常开发或数据处理中,我们经常会遇到这样的需求:如何转置一个矩阵(二维列表)? 即把矩阵的行变成列,列变成行。
如果使用 C++ 或 Java 的思维,大概率会写出这样的代码:
matrix = [[1, 2, 3],[4, 5, 6]]# 传统双重 for 循环transposed = []for i inrange(len(matrix[0])):new_row = []for row in matrix:new_row.append(row[i])transposed.append(new_row)print(transposed)# 结果: [[1, 4], [2, 5], [3, 6]]
这段代码当然能跑通,但它显得有些啰嗦,不够 Pythonic。在 Python 中,有一种被无数老手津津乐道的“神仙写法”,只需一行代码:
transposed = [list(row) for row inzip(*matrix)]我们把这行代码掰开揉碎,搞懂 zip 和 * 操作符的精妙配合。
zip()zip() 是 Python 的内置函数,它的名字非常形象——拉链。
想象一下衣服上的拉链,它是如何把两侧的链齿一一对应咬合在一起的?zip() 函数做的就是这件事:它接收多个可迭代对象(比如列表),然后把它们对应位置的元素“打包”成一个个元组。
list_a = [1, 2, 3]list_b = ['a', 'b', 'c']# 像拉链一样咬合result = list(zip(list_a, list_b))print(result)# 输出: [(1, 'a'), (2, 'b'), (3, 'c')]
为了直观理解,你可以看看下面这张图:

关键点:
zip()接收的是多个独立的列表(可迭代对象),然后把它们按列打包。
* 解包在 Python 中,* 除了表示乘法,放在可迭代对象(如列表、元组)前面时,它代表解包(Unpacking)。
你可以把包含多个子列表的二维列表想象成一个大纸箱,里面装着很多小盒子。* 的作用就是把大纸箱拆开,把里面的小盒子直接倒出来,作为独立的参数传给函数。
matrix = [[1, 2, 3], # 纸箱里的第一个小盒子[4, 5, 6] # 纸箱里的第二个小盒子]# 如果直接打印 matrix,输出的是一个大纸箱print(matrix)# 输出: [[1, 2, 3], [4, 5, 6]]# 如果用 * 解包,相当于把两个小盒子独立传给 printprint(*matrix)# 相当于 print([1, 2, 3], [4, 5, 6])# 输出: [1, 2, 3] [4, 5, 6]
[list(row) for row in zip(*matrix)]现在,我们将这两者结合起来。回到我们的单行转置代码:
[list(row) for row inzip(*matrix)]第一阶段:执行 *matrix 解包
原本的 matrix 是一个包含两个子列表的二维列表。经过 * 解包后,它的外层“纸箱”被剥离了。
此时,代码实际上变成了:zip([1, 2, 3], [4, 5, 6])
第二阶段:执行 zip() 拉链操作
此时,zip() 函数接收到了两个独立的列表。它尽职尽责地执行拉链逻辑:
1,和第二个列表的第 1 个元素 4,打包成元组 (1, 4)2,和第二个列表的第 2 个元素 5,打包成元组 (2, 5)3,和第二个列表的第 3 个元素 6,打包成元组 (3, 6)注意:如果仅仅执行 list(zip(*matrix)),得到的结果是 [(1, 4), (2, 5), (3, 6)]。虽然转置了,但内部元素是不可变的元组,而不是标准的列表矩阵。
第三阶段:列表推导式还原
为了保持矩阵内外一致的“列表”结构,我们在最外层套用了一个列表推导式 (List Comprehension):[list(row) for row in ...]
它遍历了 zip 生成的每一个元组列 row(如 (1, 4)),并将其强制转换为列表 [1, 4]。
最终,完美地拼装出了我们想要的转置矩阵:[[1, 4], [2, 5], [3, 6]]
仔细一看,这恰好就是原始矩阵的转置结果,请看下图拆解:
一行代码 完美体现了 Python 哲学的核心:优雅、简洁、表达力强。
通过 * 将矩阵的每一行解包为独立的列表参数,再由 zip() 将这些独立列表按列重新打包,这一拆一合之间,矩阵的转置就自然而然地完成了。
下次当你遇到需要按列处理二维数据,或者需要翻转行列时,不要第一时间去写嵌套的 for 循环。试着掏出 zip 和 * 这对黄金搭档,让你的代码充满 Pythonic 的魅力吧!