了解python转置脚本

时间:2017-10-18 14:43:40

标签: python zip transpose

我找到了一个名为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)是什么意思?一旦完成,我们打印一个空格,我们加入行?我只是不知道这是如何导致换位的。

任何解释都将深表感谢。

2 个答案:

答案 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填补空白。默认fillvalueNone

关于fileinput,有些人觉得方便,我更喜欢with open( ......

答案 1 :(得分:1)

  1. fileinput也支持其他文件输入方法。它可以有效地执行open(sys.argv[1],'r'),但也支持其他可能性 - 请参阅Python documentation

  2. 您对2和3的理解大致正确

  3. 对于每一行,该行被剥去空格,然后用空格分割。这导致网格表示文件的每个以空格分隔的部分。

  4. 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