属性错误:FileInput实例没有'__exit__'属性。

19

我正在尝试从多个输入文件中读取并将每个文件的第二行并排打印成表格

import sys
import fileinput

with fileinput.input(files=('cutflow_TTJets_1l.txt ', 'cutflow_TTJets_1l.txt ')) as f:
    for line in f:
        proc(line)



def proc(line):
     parts = line.split("&") # split line into parts
     if  "&" in line:    # if at least 2 parts/columns
         print parts[1] # print column 2 

但是我收到了一个“AttributeError: FileInput实例没有属性'__exit__'”的错误信息


据我所知,Python 会在 fileinput 完成后立即关闭文件——至少文档中没有提到需要手动关闭。因此,在 fileinput 中使用上下文管理器是没有意义的,也没有必要实现 __enter____exit__ - Dan Oberlam
抱歉,我不明白这如何对我有所帮助。 - Just_Newbie
解决方案是不使用上下文管理器。 - Dan Oberlam
你的 Python 版本是什么?是 Python 2.7 吗?在 Python 2 上,你可以使用 with contextlib.closing(fileinput.FileInput(..)) as file: - jfs
2个回答

32

问题在于Python 2.7.10及以上版本,fileinput模块不支持作为上下文管理器使用,即不能使用with语句,因此您需要自行处理关闭序列的操作。下面的代码应该可以解决:

f = fileinput.input(files=('cutflow_TTJets_1l.txt ', 'cutflow_TTJets_1l.txt '))

for line in f:
    proc(line)

f.close()

请注意,在Python 3的最新版本中,您可以将此模块用作上下文管理器。


对于问题的第二部分,假设每个文件的格式相似,并且具有形式为xxxxxx& xxxxx的相等数量数据行,则可以按如下方式从每个数据的第二列制作数据表:

从一个空列表开始,成为一个表,其中行将是来自每个文件的第二列条目的列表:

table = []

现在迭代遍历 fileinput 序列中的所有行,使用 fileinput.isfirstline() 检查我们是否正在处理新文件并创建一个新的行:

for line in f:
    if fileinput.isfirstline():
        row = []
        table.append(row)
    parts = line.split('&')
    if len(parts) > 1:
        row.append(parts[1].strip())

f.close()                      
现在,table将是你真正想要的转置表,其中每一行包含每个文件给定行的第二列条目。要转置列表,可以使用zip,然后循环遍历转置表的行,使用join字符串方法以逗号分隔符(或任何你想要的分隔符)打印每一行:
for row in zip(*table):
    print(', '.join(row))                             

1
这是否关闭了每个文件?还是只关闭最后一个文件(即其他文件在使用完毕后关闭)? - Dan Oberlam
1
@Just_Newbie,那是因为你在定义proc之前使用了它。请重新排列代码。 - Dan Oberlam
1
@Just_Newbie 这个问题有点棘手,需要更多信息才能回答。这两个文件的行数是否都是形如“xxxx&xxxx”的格式?如果不是,表格中应该留下空白吗?第一个文件的第7行是否总是要与第二个文件的第7行匹配? - Eric Appelt
2
@Dannnno,fileinput只是迭代序列中的每个文件,并且仅当到达上一个文件的末尾并且仍有文件剩余时才在调用next()时打开文件。 close()只是调用nextfile(),它关闭当前文件(如果已经打开)并继续序列中的下一个文件,而不实际打开该文件。 - Eric Appelt
1
@Just_Newbie - 好的,我添加了一个使用fileinput完成此操作的解决方案。 - Eric Appelt
显示剩余2条评论

4
如果某个东西有 open/close 方法,使用 contextlib.closing:
import sys
import fileinput
from contextlib import closing

with closing(fileinput.input(files=('cutflow_TTJets_1l.txt ', 'cutflow_TTJets_1l.txt '))) as f:
    for line in f:
        proc(line)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接