我想编写一个接受路径作为字符串或文件对象的函数。到目前为止,我有:
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:
会产生任何影响吗?
谢谢!
答案 0 :(得分:14)
你的代码奇怪的是,如果它传递一个打开的文件,它将关闭它。这不好。无论打开什么代码,文件都应该负责关闭它。这使得函数有点复杂:
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)
答案 1 :(得分:3)
你可以这样做:
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:关于装饰者的更详细信息。