接受文件对象或路径的Python函数

时间:2011-07-21 22:14:55

标签: python file-io

我想编写一个接受路径作为字符串或文件对象的函数。到目前为止,我有:

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 个答案:

答案 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:关于装饰者的更详细信息。