python:使用两个函数打开文件的“ with”语法

时间:2018-10-23 15:07:00

标签: python

假设我要使用以下语法打开文本文件以进行阅读:

with open(fname,'r') as f:
    # do something
    pass

但是,如果我检测到它以.gz结尾,我会调用gzip.open()。

if fname.endswith('.gz'):
    with gzip.open(fname,'rt') as f:
            # do something
            pass
else:
    with open(fname,'r') as f:
            # do something
            pass

如果“做某事”部分很长且不方便在函数中编写(例如,它将创建一个嵌套的函数,无法序列化),那么使用gzip.open或open基于的最短调用方法是fname.endswith('。gz')的返回值?

3 个答案:

答案 0 :(得分:9)

您可以将任一上下文管理器绑定到相同的名称并选择早期:

if fname.endswith('.gz'):
    context = gzip.open(fname,'rt')
else:
    context = open(fname,'r')

with context as f:
    # do the same thing in either case

这允许一些不错的模式,例如,如果输入可能是打开的文件句柄,则可以使用contextlib.nullcontext在给定情况下在with块中获得无操作。 / p>

答案 1 :(得分:9)

上下文管理器帮助关闭对象。

您不必创建用作上下文管理器的对象,但是同时您可以使用with输入上下文。 open()gzip.open()调用返回一个恰好是上下文管理器的新对象,您可以在输入上下文之前创建它们:

if fname.endswith('.gz'):
    f = gzip.open(fname,'rt')
else:
    f = open(fname, 'r')

with f:
    # do something

在两种情况下,对象在进入上下文时都返回self,因此在这里无需使用as f

此外,函数是一等公民,因此您还可以使用变量存储函数,然后在with语句中调用它以创建上下文管理器和文件对象:

if fname.endswith('.gz'):
    opener = gzip.open
else:
    opener = open

with opener(fname, 'rt') as f:  # yes, both open and gzip.open support mode='rt'
    # do something

与这里的其他方法相比,它并不能真正为您带来任何好处,但是您可以根据需要使用字典将扩展名映射到可调用对象。

最重要的是with calls context-manager hook methods,无非是一无所有。 with之后的表达式应该提供这样的管理器,但是创建该对象不受上下文管理协议的约束。

答案 2 :(得分:2)

with gzip.open(fname, 'rt') if fname.endswith('.gz') else open(fname, 'r') as f:
    # do something
    pass