我找到了一个名为transpose_file.py的Python脚本,它可以转换空格分隔的文件。它看起来像这样:
import fileinput
m = []
for line in fileinput.input():
m.append(line.strip().split(" "))
for row in zip(*m):
print " ".join(row)
我想确保我理解每一行的作用,因为我对Python很陌生。
1)首先,我们导入一个名为fileinput的模块,它允许您读取文件并通过它们进行解析?不确定为什么使用简单的open(sys.argv [1],'r')作为f等不起作用
2)创建一个名为m
的空列表3)对于输入文件中的每一行,删除行尾的任何空格,制表符或换行符,并使空格成为分隔符(即输入文件是分隔的)
4)对于每一行......不确定其余的意思。 zip(* m)是什么意思?一旦完成,我们打印一个空格,我们加入行?我只是不知道这是如何导致换位的。
任何解释都将深表感谢。
答案 0 :(得分:1)
您的分析基本上是正确的。
请注意
line.strip().split(" ")
有点脆弱。它剥离了所有领先和从行中尾随空格,然后使用单个空格作为分隔符将行拆分为字符串列表。如果该行包含多个空格的运行,或者它包含选项卡,则可能无法执行此操作。
zip
函数并行迭代其参数,从每个arg中的相应项构建元组。所以首先它会生成所有第一项的元组,然后是所有第二项,等等。
例如:
for t in zip([1, 2, 3], [4, 5, 6], [7, 8, 9]):
print(t)
print()
<强>输出强>
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)
如您所见,这会导致换位。
我们可以使用*
&#34; splat&#34;运算符将序列列表传递给zip
,&#34; splat&#34; operator解压缩列表,以便zip
将每个序列视为一个单独的arg。
lst = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
for t in zip(*lst):
print(t)
这提供与以前相同的输出。
&#34; splat&#34; operator不仅仅是zip
的一个特殊功能:你可以在任何带有多个参数的函数上使用它。还有&#34;双击&#34; operator **
,它将字典解包为keyword = value对。
如果序列长度不同,那么当最短序列中没有剩余项目时,zip
会停止。但是,标准itertools
模块中有一个相关功能:itertools.zip_longest
,它带有一个可选的fillvalue
。它一直持续到最长的序列耗尽,使用fillvalue
填补空白。默认fillvalue
为None
。
关于fileinput
,有些人觉得方便,我更喜欢with open(
......
答案 1 :(得分:1)
fileinput
也支持其他文件输入方法。它可以有效地执行open(sys.argv[1],'r')
,但也支持其他可能性 - 请参阅Python documentation。
您对2和3的理解大致正确
对于每一行,该行被剥去空格,然后用空格分割。这导致网格表示文件的每个以空格分隔的部分。
zip(*)
实际上是Python的转置运算符。例如:
In [1]: data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
In [2]: data
Out[2]: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
In [3]: transp = list(zip(*data))
In [4]: transp
Out[4]: [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
您必须将其强制转换为list
,因为zip
会返回一个可迭代的。 zip
可能更常用于&#34; zip&#34;两个列表,所以你可以一起迭代它们:
In [1]: list(zip(["one", "three", "five"], ["two", "four", "six"]))
Out[1]: [('one', 'two'), ('three', 'four'), ('five', 'six')]
这也很好documented。
*
运算符将网格的每个子列表分隔为zip
的单独参数。
" ".join
将每个字符串连接在一个带有空格的iterable中 - 例如
In [1]: " ".join(["foo", "bar", "baz"])
Out[1]: 'foo bar baz'
这只是将空格分隔符放回到新转换的字符串系列中。这又是documented。