在 python 中打开/关闭可选文件的干净方法?

问题描述 投票:0回答:5

我的代码:

fh = None
if args.optional_input_file_path is not None:
    fh = open(args.optional_input_file_path)

my_function(foo, bar, fh)

if args.optional_input_file_path is not None:
    fh.close()

我不喜欢我需要写

if args.optional_input_file is not None:
两次。

my_function
内移动条件逻辑也不理想,因为我故意将
IO
对象传递给函数而不是文件路径,以便于测试。

有没有更简洁的方法来实现同样的事情?

我希望能够只写一次

my_function(foo, bar, fh)
,并让
fh
是一个
IO
对象或
None
,这取决于
args.optional_input_file_path
的值。

python file-handling
5个回答
2
投票

使用自定义 context manager 传播

None
但在其他方面表现得像
open

import contextlib


@contextlib.contextmanager
def open_not_none(file, *args, **kwargs):
    if file is not None:
        with open(file, *args, **kwargs) as f:
            yield f
    else:
        yield None

可以用作

with open_not_none(args.optional_input_file_path, "r") as fh:
    my_function(foo, bar, fh)

这使您可以保留在 with 语句 中打开文件的所有好处,同时避免为

my_function
和非
None
情况重复调用
None
。如果您愿意,您也可以使用
typing.overload
丰富地键入提示。


1
投票

试试这个

my_function(foo, bar, open(args.file_path) if args.file_path else None)

因为没有引用打开的文件,它会在下一次GC时自动关闭


0
投票
fh = None
if args.optional_input_file_path is not None:
    fh = open(args.optional_input_file_path)

my_function(foo, bar, fh)

fh = None
# del fh  # faster than setting it to None

再次将 fh 设置为 None 应该会触发它的删除,如果文件没有存储在其他地方,这会导致文件被关闭。

如果它存储在其他地方,那么您不再有责任关闭它,这称为 RAII。


0
投票

contextlib 的文档建议以下内容来处理可选上下文:

def process_file(filename):
    if filename is not None:
        cm = open(filename)
    else:
        cm = nullcontext()

    with cm as file:  # file will be None if no filename
        my_function(...., file)

-1
投票

您可以为此目的使用装饰器。

def open_file(nested_function):
    def decorated(foo, bar, fh):
        fh = open(args.optional_input_file_path)
        nested_function(foo, bar, fh)
        fh.close()
    return decorated

fh = None
if args.optional_input_file_path is not None:
    decorated = open_file(my_function)
    decorated(foo, bar, fh)
else:
    my_function(foo, bar, fh)

© www.soinside.com 2019 - 2024. All rights reserved.