Python 从文件创建两个词典时保持文件打开

Python 从文件创建两个词典时保持文件打开,python,file,dictionary,io,Python,File,Dictionary,Io,我打开了一个文件,我把它命名为“myfile”;我想用它创建两个不同的字典,但是文件关闭了,我假设是因为我在第一个循环中创建了第一个字典。 对于直方图,我得到了一个空字典,我尝试使用myfile作为x,在第二个循环中使用x而不是f,我得到了这个“ValueError:I/O对闭合文件的操作” 另外,我在一个类的函数中这样做,如果这有区别的话 有人知道怎么做吗 d = {} d2 ={} with myfile as f: next(f) f

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

另外,我在一个类的函数中这样做,如果这有区别的话

有人知道怎么做吗

    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)

第一次循环遍历迭代器就是在耗尽迭代器。因此,当您再次尝试循环时,就没有什么可看的了

把你所有的逻辑放在同一个循环中。我不太确定您的循环应该做什么,但它看起来像您的第一个循环,它应该只应用于每个奇数(0索引)行,这可以通过
枚举
轻松完成。第二个循环似乎适用于每一行,因此我将从该循环开始,然后将“第一个”循环的功能添加到其中;大概是这样的:

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)
try:
    ...  ## use myfile here instead of f
finally:
    myfile.close()

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


然而,@henry keiter建议只对数据进行一次循环,这一点应该认真对待。

我同意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 open(...) as f:
    ...
但是编写的代码已经打开了它。这意味着此处的
myfile
变量已在较早时初始化,并且仍然可以使用
在此
之外进行访问

如果我们使用
try
/
finally
,我们会更公平地对待代码,如下所示:

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)
try:
    ...  ## use myfile here instead of f
finally:
    myfile.close()

如果代码明确说明
myfile
将保证在
try
/
结束时关闭,那么最后

为什么需要两个循环?你不能只循环一次
f
吗?你可以使用seek()将当前位置设置回文件的开头。我在循环之间添加了myfile.seek(0),它就工作了。我想为这个问题添加一个答案,但我没有足够的声誉,所以我不能。@user2926009这也行得通,不过如果你的文件很大或者你经常运行这个,你可能需要将代码重构为一个循环,这样它会运行得更快。