假设我要使用以下语法打开文本文件以进行阅读:
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')的返回值?
答案 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