【发布时间】:2015-11-26 16:28:12
【问题描述】:
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常是这样的:
with open(myfile) as fh:
# do stuff with open file handle...
确保在退出with 块时始终关闭文件。但是,如果在函数中传递了现有的文件句柄,则它可能不会自行关闭。
考虑下面的函数,它接受一个打开的文件对象或一个给出文件路径的字符串作为它的参数。如果它传递了一个文件路径,它可能应该像上面那样写。否则应省略with 语句。这会导致重复代码:
def foo(f):
if isinstance(f, basestring):
# Path to file, need to open
with open(f) as fh:
# do stuff with fh...
else:
# Assume open file
fh = f
# do the same stuff...
这当然可以通过定义一个辅助函数并在两个地方调用它来避免,但这似乎不优雅。我想到的更好的方法是定义一个包装对象的上下文管理器类,如下所示:
class ContextWrapper(object):
def __init__(self, wrapped):
self.wrapped = wrapped
def __enter__(self):
return self.wrapped
def __exit__(self, *args):
pass
def foo(f):
if isinstance(f, basestring):
cm = open(f)
else:
cm = ContextWrapper(f)
with cm as fh:
# do stuff with fh...
这可行,但除非有一个内置对象可以执行此操作(我认为没有),否则我要么必须将该对象复制粘贴到任何地方,要么总是必须导入我的自定义实用程序模块。我觉得我错过了一种更简单的方法。
【问题讨论】:
-
我想不出一个很好的理由来编写可以接受要么 路径 或 打开文件句柄的代码。在那种极端情况下,我建议您编写自己的包装器(就像您所做的那样)
-
我认为辅助函数可能更加优雅。您在
foo中所做的很多工作是将参数放入正确类型的对象——打开的文件句柄。将执行核心工作的代码分解为假定打开文件句柄的帮助程序,我认为整体结果更加清晰。实际上,“helper”本身可能是一个合法的公共函数,“foo_from_path”在打开文件处理程序后简单地调用“foo”。 -
@AdamSmith 对于它的价值,这是一个常见的设计,比如说,numpy。例如,
np.load采用 string or a fileobj。我想它只是为了让一些代码更简洁,而且由于 numpy 经常被交互使用,这并不是不明智的。 -
@jme 感谢您的上下文! :)
-
Python 3.x 有更优雅的解决方案,见:stackoverflow.com/questions/41251850
标签: python python-2.7 contextmanager