【问题标题】:Keeping file open while creating two dictionaries from the file从文件创建两个字典时保持文件打开
【发布时间】:2013-11-07 20:02:36
【问题描述】:

我打开了一个文件并将其命名为“myfile”;我想从中创建两个不同的字典,但文件对我关闭,我假设是因为我在第一个循环中创建了第一个字典。 我得到一个直方图的空字典,我尝试将 myfile 用作 x 并在第二个循环中使用 x 而不是 f,我得到这个“ValueError: I/O operation on closed file”。

另外,如果这会有所不同,我会在一个类的函数中执行此操作。

有人知道怎么做吗?

    d = {}
    d2 ={}
    with myfile as f:
        next(f)
        for line in f:
            k, v = line.split()
            d[int(k)] = int(v)
            next(f)

        for line in f:
            items = line.split()
            key, values = int(items[0]), items[1:]
            d2.setdefault(key, []).extend(values)


    hist = defaultdict(list)
    for key, values in d2.iteritems():
        hist[len(values)].append(key)
    histogram = dict(hist)

【问题讨论】:

  • 为什么需要两个循环?你不能只循环一次f 吗?
  • 您可以使用 seek() 将当前位置设置回文件的开头。

标签: python file dictionary io


【解决方案1】:

您只是在第一次循环遍历它时耗尽了迭代器。因此,当您再次尝试循环时,什么都看不到了。

只需将所有逻辑放在同一个循环中即可。我不太确定你的循环应该做什么,但它看起来像你拥有的第一个循环,它应该只适用于每个奇数(0 索引)行,这很容易通过 @987654321 完成@。第二个循环似乎适用于每一行,所以我将从该循环开始,然后将“第一个”循环的功能添加到它;像这样:

with myfile as f: # Better:  with open('/some/file.txt', 'rb') as f:
    for i, line in enumerate(f):
        # "Second" loop
        items = line.split()
        key, values = int(items[0]), items[1:]
        d2.setdefault(key, []).extend(values)

        # "First" loop
        if i % 2 != 0: # Only process odd-numbered lines
            k, v = items
            d[int(k)] = int(v)

【讨论】:

  • 我在我的循环之间添加了 myfile.seek(0) 并且它起作用了。我想为此添加一个答案,但我没有足够的声誉,所以我不能。
  • @user2926009 这也可以,但如果您的文件很大或者您经常运行此程序,您可能希望将代码重构为单个循环,以便运行得更快。跨度>
【解决方案2】:

我同意 Henry 的观点:除非您确实需要执行两遍算法,否则不要执行 seek()

你不能有什么理由吗?

此外,在第一个循环中使用 next(f) 看起来很可疑:通常,如果您正在迭代某个东西,您不想对支持迭代的那个东西做任何其他事情。

我期待的是这样的:

with myfile as f:    ## FIXME: this is suspect.  'myfile' is accessible outside this
                     ## `with` already, so there's something weird here. 
    for (index, line) in itertools.izip(itertools.count(), f):
        if index % 2 == 1:
            k, v = line.split()
            d[int(k)] = int(v)

        items = line.split()
        key, values = int(items[0]), items[1:]
        d2.setdefault(key, []).extend(values)

您可以在其中对文件进行单遍迭代。原始代码中的第一个循环似乎只关心文件中的奇数行,所以这次重写试图表达这个想法。


顺便说一句:这里使用with 看起来不太好。如果我们希望with 负责资源的打开和关闭,我们通常会这样做,并在with 的正文中为其命名:

with open(...) as f:
    ...

但是编写的代码已经打开了它。这意味着这里的 myfile 变量已被较早初始化,并且仍然可以在此 with 之外访问。

如果我们使用try/finally,我们会更公正地处理代码,如下所示:

try:
    ...  ## use myfile here instead of f
finally:
    myfile.close()

代码更清楚地表明myfile 将保证在try/finally 结束时关闭。

【讨论】:

    【解决方案3】:

    要解决您提出的问题,请在第一个循环后致电f.seek(0)

    但是,@henry-keiter 建议只循环一次数据,应该认真对待。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-25
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 2016-09-03
      • 2012-04-10
      相关资源
      最近更新 更多