接受文件对象或路径的Python函数
我想写一个函数,这个函数可以接受一个路径(用字符串表示)或者一个文件对象。到目前为止,我的代码是:
def awesome_parse(path_or_file):
if isinstance(path_or_file, basestring):
f = open(path_or_file, 'rb')
else:
f = path_or_file
with f as f:
return do_stuff(f)
这里的 do_stuff
是用来处理一个打开的文件对象的。
有没有更好的方法来实现这个?使用 with f as f:
会有什么影响吗?
谢谢!
2 个回答
6
你可以这样做:
def awesome_parse(do_stuff):
"""Decorator to open a filename passed to a function
that requires an open file object"""
def parse_path_or_file(path_or_file):
"""Use a ternary expression to either open the file from the filename
or just pass the extant file object on through"""
with (open(path_or_file, 'rb')
if isinstance(path_or_file, basestring)
else path_or_file) as f:
return do_stuff(f)
return parse_path_or_file
然后当你声明任何对打开的文件对象进行操作的函数时:
@awesome_parse
def do_things(open_file_object):
"""This will always get an open file object even if passed a string"""
pass
@awesome_parse
def do_stuff(open_file_object):
"""So will this"""
pass
编辑2:关于装饰器的更详细信息。
20
你代码中有个奇怪的地方,就是如果它接收到一个打开的文件,它会把这个文件关闭。这可不好。打开文件的代码应该负责把它关闭。不过,这样会让这个函数变得有点复杂:
def awesome_parse(path_or_file):
if isinstance(path_or_file, basestring):
f = file_to_close = open(path_or_file, 'rb')
else:
f = path_or_file
file_to_close = None
try:
return do_stuff(f)
finally:
if file_to_close:
file_to_close.close()
你可以通过写自己的上下文管理器来简化这个问题:
@contextlib.contextmanager
def awesome_open(path_or_file):
if isinstance(path_or_file, basestring):
f = file_to_close = open(path_or_file, 'rb')
else:
f = path_or_file
file_to_close = None
try:
yield f
finally:
if file_to_close:
file_to_close.close()
def awesome_parse(path_or_file):
with awesome_open(path_or_file) as f:
return do_stuff(f)