一次打开多个(未指定数量)文件并确保它们正确关闭
我知道我可以使用类似的方法打开多个文件,
with open('a', 'rb') as a, open('b', 'rb') as b:
但我有一种情况,我有一个要打开的文件列表,并且想知道当文件数量事先未知时执行相同操作的首选方法是什么。类似的东西
with [ open(f, 'rb') for f in files ] as fs:
(但是由于列表没有实现__exit__
,所以失败并出现AttributeError
)
我不介意使用类似的东西,
try:
fs = [ open(f, 'rb') for f in files ]
....
finally:
for f in fs:
f.close()
但我不确定如果某些尝试打开文件时抛出文件。 fs
是否会在 finally
块中正确定义,并包含成功打开的文件?
I am aware that I can open multiple files with something like,
with open('a', 'rb') as a, open('b', 'rb') as b:
But I have a situation where I have a list of files to open and am wondering what the preferred method is of doing the same when the number of files is unknown in advance. Something like,
with [ open(f, 'rb') for f in files ] as fs:
(but this fails with an AttributeError
since list doesn't implement __exit__
)
I don't mind using something like,
try:
fs = [ open(f, 'rb') for f in files ]
....
finally:
for f in fs:
f.close()
But am not sure what will happen if some files throw when trying to open them. Will fs
be properly defined, with the files that did manage to open, in the finally
block?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不,除非所有
open()
调用成功完成,否则您的代码不会初始化fs
。但这应该可以工作:另请注意, f.close() 可能会失败,因此您可能希望捕获并忽略(或以其他方式处理)那里的任何失败。
No, your code wouldn't initialise
fs
unless allopen()
calls completed successfully. This should work though:Note also that f.close() could fail so you may want to catch and ignore (or otherwise handle) any failures there.
当然,为什么不呢,这是一个可以做到这一点的食谱。创建一个上下文管理器“池”,它可以输入任意数量的上下文(通过调用它的
enter()
方法),并且它们将在套件结束时被清理。例如:
警告:上下文管理器不应在其 __exit__() 方法中引发异常,但如果引发异常,则此方案不会对所有上下文管理器进行清理。同样,即使每个上下文管理器都指示应忽略异常(通过从其退出方法返回 True),这仍然允许引发异常。
Sure, why not, Here's a recipe that should do it. Create a context manager 'pool' that can enter an arbitrary number of contexts (by calling it's
enter()
method) and they will be cleaned up at the end of the end of the suite.For example:
Caveats: context managers aren't supposed to raise exceptions in their
__exit__()
methods, but if they do, this recipe doesn't do the cleanup for all the context managers. Similarly, even if every context manager indicates that an exception should be ignored (by returningTrue
from their exit methods), this will still allow the exception to be raised.类
ExitStack
来自 < href="https://docs.python.org/3/library/contextlib.html#module-contextlib" rel="noreferrer">contextlib
模块提供您所需的功能寻找。文档中提到的规范用例是管理动态数量的文件。
The class
ExitStack
from thecontextlib
module provides the functionality you are looking for.The canonical use-case that is mentioned in the documentation is managing a dynamic number of files.
尝试打开文件、尝试读取文件以及(极少数情况下)尝试关闭文件时可能会发生错误。
因此,基本的错误处理结构可能如下所示:
这确保如果
stream
变量存在,则始终会调用close
。如果stream
不存在,则open
一定失败,因此没有要关闭的文件(在这种情况下, except 块将立即执行)。您真的需要并行打开文件,还是可以顺序处理它们?如果是后者,则应将类似上述文件处理代码的内容放入一个函数中,然后为列表中的每个路径调用该函数。
Errors can occur when attempting to open a file, when attempting to read from a file, and (very rarely) when attempting to close a file.
So a basic error handling structure might look like:
This ensures that
close
will always be called if thestream
variable exists. Ifstream
doesn't exist, thenopen
must have failed, and so there is no file to close (in which case, the except block will be executed immediately).Do you really need to have the files open in parallel, or can they be processed sequentially? If the latter, then something like the above file-processing code should be put in a function, which is then called for each path in the list.
感谢您的所有回答。受到大家的启发,我提出了以下建议。我认为(希望)它能按我的预期工作。我不确定是否将其作为问题的答案或补充发布,但认为答案更合适,因为如果它未能满足我的要求,可以对其进行适当的评论。
它可以像这样使用..
或像这样..
在这里,
Thanks for all your answers. Taking inspiration from all of you, I have come up with the following. I think (hope) it works as I intended. I wasn't sure whether to post it as an answer or an addition to the question, but thought an answer was more appropriate as then if it fails to do what I'd asked it can be commented on appropriately.
It can be used for example like this ..
or like this ..
And here it is,