【问题标题】:iterating over file object in Python does not work, but readlines() does but is inefficient在 Python 中迭代文件对象不起作用,但 readlines() 可以,但效率低下
【发布时间】:2012-11-07 07:10:22
【问题描述】:

在下面的代码中,如果我使用:

for line in fin:

它只为'a'执行

但如果我使用:

wordlist = fin.readlines()
for line in wordlist:

然后它执行一个 thru z。

readlines() 一次读取整个文件,这是我不想要的。

如何避免这种情况?

def avoids():
    alphabet = 'abcdefghijklmnopqrstuvwxyz'
    num_words = {}

    fin = open('words.txt')

    for char in alphabet:
      num_words[char] = 0
      for line in fin:
        not_found = True
        word = line.strip()
        if word.lower().find(char.lower()) != -1:
          num_words[char] += 1
    fin.close()
    return num_words

【问题讨论】:

  • 你有两个循环 - 在任何情况下你都需要整个文件 - 我的建议是全部阅读。
  • @Greg Lafrance:除了Artsiom Rudzenka 的我的建议是通读。...我的建议是:通读一次!!! 通过将循环逻辑反转为foreach line in file: foreach letter in alphabet(而不是字母表中的 foreach 字母:文件中的 foreach 行...通常 I/O 应该始终是两个循环的外部,因为 I/O 慢得多得多得多而不是内存访问。

标签: python


【解决方案1】:

语法for line in fin 只能使用一次。在你这样做之后,你已经用尽了文件并且你不能再次读取它,除非你通过fin.seek(0)“重置文件指针”。相反,fin.readlines() 会给你一个列表,你可以一遍又一遍地迭代。


我认为使用 Counter (python2.7+) 进行简单的重构可以让您省去这个麻烦:

from collections import Counter
with open('file') as fin:
    result = Counter()
    for line in fin:
        result += Counter(set(line.strip().lower()))

这将计算文件中包含特定字符的单词数(每行 1 个单词)(我相信这是您的原始代码......如果我错了,请纠正我)

您也可以使用defaultdict (python2.5+) 轻松做到这一点:

from collections import defaultdict
with open('file') as fin:
    result = defaultdict(int)
    for line in fin:
        chars = set(line.strip().lower())
        for c in chars:
            result[c] += 1

最后,把它踢老派——我什至不知道setdefault 是什么时候引入的......:

fin = open('file')
result = dict()
for line in fin:
    chars = set(line.strip().lower())
    for c in chars:
        result[c] = result.setdefault(c,0) + 1

fin.close()

【讨论】:

  • 这是关键。非常感谢! "fin 中 line 的语法只能使用一次。这样做之后,文件已经用尽,无法再次读取,除非通过 fin.seek(0) 来“重置文件指针””跨度>
  • @GregLafrance -- 如果这有助于您解决问题,请随时接受(点击解决方案旁边的小复选标记)。
【解决方案2】:

您有三个选择:

  1. 还是读入整个文件。
  2. 在尝试再次迭代之前返回文件的开头。
  3. 重新构建您的代码,使其无需多次迭代文件。

【讨论】:

    【解决方案3】:

    试试:

    from collections import defaultdict
    from itertools import product
    
    def avoids():
        alphabet = 'abcdefghijklmnopqrstuvwxyz'
    
        num_words = defaultdict(int)
    
        with open('words.txt') as fin:
            words = [x.strip() for x in fin.readlines() if x.strip()]
    
        for ch, word in product(alphabet, words):
            if ch not in word:
                 continue
            num_words[ch] += 1
    
        return num_words
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 2021-05-25
      • 2017-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多