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

16 投票
2 回答
8990 浏览
提问于 2025-04-16 22:02

我想写一个函数,这个函数可以接受一个路径(用字符串表示)或者一个文件对象。到目前为止,我的代码是:

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)

撰写回答