2009-12-02 156 views
9

我经常写这样的代码:如何干净地遍历两个文件并行在Python

lines = open('wordprob.txt','r').readlines() 
words = open('StdWord.txt','r').readlines() 
i = 0 
for line in lines: 
    v = [eval(s) for s in line.split()] 
    if v[0] > v[1]: 
     print words[i].strip(), 
    i += 1 

是否有可能避免使用变量i和使程序更短?

谢谢。

回答

14

你可以尝试使用枚举,

http://docs.python.org/tutorial/datastructures.html#looping-techniques

lines = open('wordprob.txt','r').readlines() 
words = open('StdWord.txt','r').readlines() 
for i,line in enumerate(lines): 
     v = [eval(s) for s in line.split()] 
     if v[0] > v[1]: 
       print words[i].strip() 
+5

我不喜欢这个解决方案,因为它将所有数据读入RAM中。只要数据适合内存就可以,这很简单,但我更喜欢适用于任何大小数据集的通用解决方案。 – steveha 2013-01-13 21:52:42

1

enumerate看看:

>>> for i, season in enumerate(['Spring', 'Summer', 'Fall', 'Winter']): 
...  print i, season 
0 Spring 
1 Summer 
2 Fall 
3 Winter 
5

一般来说枚举是一个很好的解决方案。在这种情况下,你可以这样做:

lines = open('wordprob.txt','r').readlines() 
words = open('StdWord.txt','r').readlines() 
for word, line in zip(words, lines): 
    v = [eval(s) for s in line.split()] 
    if v[0] > v[1]: 
      print word.strip(), 
+4

'zip()'是一个很好的方式来将两件事情一起循环。但是,在Python 2.x中,它将构建一个包含所有值的列表,因此这将占用大量内存。你可以用'itertools.izip()'得到同样的效果,它会返回一个一次返回一个值的迭代器。你可以'导入itertools'然后执行:'for word,在itertools.izip中的行(open('wordprob.txt'),open('StdWord.txt')):' – steveha 2009-12-02 04:52:57

+0

@steveha:或者,通过执行'from future_builtins import map,filter,zip'来实现Py3版本的功能,并用Py3迭代器版本替换Py2版本。 – ShadowRanger 2017-06-03 00:46:01

20

它看起来像你不在乎什么i值。您只是将它用作配对lineswords的方法。因此,我建议您一次读一行,并同时读一个字。然后他们会匹配。

此外,当您使用.readlines()时,您将所有输入一次读入内存。对于大量输入,这会很慢。对于这个简单的代码,一次只需要一行代码。由open()返回的文件对象可以充当一次返回一行的迭代器。

如果可以,应该避免使用eval()。在一个简单的练习中,您知道输入的数据是什么,这非常安全,但是如果您从外部获取数据,使用eval()可能会使您的计算机受到攻击。有关更多信息,请参见this page。我将编写我的示例代码,假设您使用eval()将文本转换为float值。 float()也可以使用整数字符串值:float('3')将返回3.0

此外,看起来输入行只能有两个值。如果一行有额外的值,你的代码将不会检测到这种情况。我们可以更改代码以明确地从分割线中解压缩两个值,然后如果有两个以上的值,Python将引发异常。另外,代码会稍微好一些。

因此,这里是我建议的这个例子的改写:

lines = open('wordprob.txt','rt') 
words = open('StdWord.txt','rt') 

for line in lines: 
    word = words.next().strip() # in Python 3: word = next(words).strip() 
    a, b = [float(s) for s in line.split()] 
    if a > b: 
     print word, # in Python 3: print(word + ' ', end='') 

编辑:这里是同一个解决方案,但使用izip()

import itertools 
lines = open('wordprob.txt','rt') 
words = open('StdWord.txt','rt') 

# in Python 3, just use zip() instead of izip() 
for line, word in itertools.izip(lines, words): 
    word = word.strip() 
    a, b = [float(s) for s in line.split()] 
    if a > b: 
     print word, # in Python 3: print(word + ' ', end='') 

在Python 3,内置zip()返回迭代器,所以你可以使用,而不是需要import itertools

编辑: 最好的做法是使用with语句来确保文件正确关闭,无论如何。在Python的最新版本中,您可以使用多个语句,我将在我的解决方案中执行此操作。另外,我们可以像解开一个列表一样简单地解压缩生成器表达式,所以我改变了将a, b设置为使用生成器表达式的行;这应该稍微快一点。除非我们打算使用它,否则我们不需要去除word。把更改放在一起得到:

from itertools import izip 

with open('wordprob.txt','rt') as lines, open('StdWord.txt','rt') as words: 
    # in Python 3, just use zip() instead of izip() 
    for line, word in izip(lines, words): 
     a, b = (float(s) for s in line.split()) 
     if a > b: 
      print word.strip(), # in Python 3: print(word.strip() + ' ', end='') 
+0

感谢您的宝贵意见! – 2009-12-02 08:48:34

+0

非常欢迎你! :-) – steveha 2009-12-02 19:09:19