当前位置:首页>python>一行代码搞定矩阵转置:深入理解 Python 中的 zip 与星号解包操作符

一行代码搞定矩阵转置:深入理解 Python 中的 zip 与星号解包操作符

  • 2026-10-09 01:10:13
一行代码搞定矩阵转置:深入理解 Python 中的 zip 与星号解包操作符

通过拆解 [list(row) for row in zip(*matrix)] 这行代码,彻底搞懂 Python 中 zip() 函数与 * 解包操作符的底层逻辑,培养 Pythonic 的编程思维。

引言

在 Python 的日常开发或数据处理中,我们经常会遇到这样的需求:如何转置一个矩阵(二维列表)? 即把矩阵的行变成列,列变成行。

如果使用 C++ 或 Java 的思维,大概率会写出这样的代码:

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
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 中,有一种被无数老手津津乐道的“神仙写法”,只需一行代码:

  • 1
transposed = [list(row) for row inzip(*matrix)]

我们把这行代码掰开揉碎,搞懂 zip 和 * 操作符的精妙配合。


基础拆解一:拉链函数 zip()

zip() 是 Python 的内置函数,它的名字非常形象——拉链。
想象一下衣服上的拉链,它是如何把两侧的链齿一一对应咬合在一起的?zip() 函数做的就是这件事:它接收多个可迭代对象(比如列表),然后把它们对应位置的元素“打包”成一个个元组。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
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)。

你可以把包含多个子列表的二维列表想象成一个大纸箱,里面装着很多小盒子。* 的作用就是把大纸箱拆开,把里面的小盒子直接倒出来,作为独立的参数传给函数。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
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)]

现在,我们将这两者结合起来。回到我们的单行转置代码:

  • 1
[list(row) for row inzip(*matrix)]

第一阶段:执行 *matrix 解包
原本的 matrix 是一个包含两个子列表的二维列表。经过 * 解包后,它的外层“纸箱”被剥离了。
此时,代码实际上变成了:
zip([1, 2, 3], [4, 5, 6])

第二阶段:执行 zip() 拉链操作
此时,zip() 函数接收到了两个独立的列表。它尽职尽责地执行拉链逻辑:

  • 取第一个列表的第 1 个元素 1,和第二个列表的第 1 个元素 4,打包成元组 (1, 4)
  • 取第一个列表的第 2 个元素 2,和第二个列表的第 2 个元素 5,打包成元组 (2, 5)
  • 取第一个列表的第 3 个元素 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 的魅力吧!

参考 (References)

最新文章

随机文章