如何在Python函数中接受文件名和类文件对象?

发布于 2024-12-02 05:14:23 字数 655 浏览 0 评论 0 原文

在我的代码中,我有一个 load_dataset 函数,它读取文本文件并进行一些处理。最近,我考虑添加对类文件对象的支持,并且我想知道对此的最佳方法。目前我想到了两种实现:

首先,类型检查:

if isinstance(inputelement, basestring):
   # open file, processing etc
# or
# elif hasattr(inputelement, "read"):
elif isinstance(inputelement, file):
   # Do something else

或者,两个不同的论点:

def load_dataset(filename=None, stream=None):
    if filename is not None and stream is None:
        # open file etc
    elif stream is not None and filename is None:
        # do something else

但这两种解决方案都没有让我太信服,尤其是第二个,因为我看到了太多的陷阱。

将类似文件的对象或字符串接受到执行文本读取的函数的最干净(也是最Pythonic)的方法是什么?

In my code, I have a load_dataset function that reads a text file and does some processing. Recently I thought about adding support to file-like objects, and I wondered over the best approach to this. Currently I have two implementations in mind:

First, type checking:

if isinstance(inputelement, basestring):
   # open file, processing etc
# or
# elif hasattr(inputelement, "read"):
elif isinstance(inputelement, file):
   # Do something else

Alternatively, two different arguments:

def load_dataset(filename=None, stream=None):
    if filename is not None and stream is None:
        # open file etc
    elif stream is not None and filename is None:
        # do something else

Both solutions however don't convince me too much, especially the second as I see way too many pitfalls.

What is the cleanest (and most Pythonic) way to accept a file-like object or string to a function that does text reading?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

你爱我像她 2024-12-09 05:14:23

将文件名或类文件对象作为参数的一种方法是实现 此处找到实现,我引用是为了一个独立的答案:

class open_filename(object):
"""Context manager that opens a filename and closes it on exit, but does
nothing for file-like objects.
"""
def __init__(self, filename, *args, **kwargs):
    self.closing = kwargs.pop('closing', False)
    if isinstance(filename, basestring):
        self.fh = open(filename, *args, **kwargs)
        self.closing = True
    else:
        self.fh = filename

def __enter__(self):
    return self.fh

def __exit__(self, exc_type, exc_val, exc_tb):
    if self.closing:
        self.fh.close()

    return False

然后可能的用法:

def load_dataset(file_):
    with open_filename(file_, "r") as f:
        # process here, read only if the file_ is a string

One way of having either a file name or a file-like object as argument is the implementation of a context manager that can handle both. An implementation can be found here, I quote for the sake of a self contained answer:

class open_filename(object):
"""Context manager that opens a filename and closes it on exit, but does
nothing for file-like objects.
"""
def __init__(self, filename, *args, **kwargs):
    self.closing = kwargs.pop('closing', False)
    if isinstance(filename, basestring):
        self.fh = open(filename, *args, **kwargs)
        self.closing = True
    else:
        self.fh = filename

def __enter__(self):
    return self.fh

def __exit__(self, exc_type, exc_val, exc_tb):
    if self.closing:
        self.fh.close()

    return False

Possible usage then:

def load_dataset(file_):
    with open_filename(file_, "r") as f:
        # process here, read only if the file_ is a string
你另情深 2024-12-09 05:14:23

不要同时接受文件和字符串。如果您要接受类似文件的对象,则意味着您不会检查类型,只需在实际参数上调用所需的方法(readwrite , ETC。)。如果您要接受字符串,那么您最终将open-ing 文件,这意味着您将无法模拟参数。所以我会说接受文件,让调用者向您传递一个类似文件的对象,并且不检查类型。

Don't accept both files and strings. If you're going to accept file-like objects, then it means you won't check the type, just call the required methods on the actual parameter (read, write, etc.). If you're going to accept strings, then you're going to end up open-ing files, which means you won't be able to mock the parameters. So I'd say accept files, let the caller pass you a file-like object, and don't check the type.

扮仙女 2024-12-09 05:14:23

我正在使用上下文管理器包装器。当它是文件名 (str) 时,退出时关闭文件。

@contextmanager
def fopen(filein, *args, **kwargs):
    if isinstance(filein, str):  # filename
        with open(filein, *args, **kwargs) as f:
            yield f
    else:  # file-like object
        yield filein

然后你可以像这样使用它:

with fopen(filename_or_fileobj) as f:
    # do sth. with f

I'm using a context manager wrapper. When it's a filename (str), close the file on exit.

@contextmanager
def fopen(filein, *args, **kwargs):
    if isinstance(filein, str):  # filename
        with open(filein, *args, **kwargs) as f:
            yield f
    else:  # file-like object
        yield filein

Then you can use it like:

with fopen(filename_or_fileobj) as f:
    # do sth. with f
就此别过 2024-12-09 05:14:23

Python遵循鸭子类型,您可以通过对象中需要的函数检查这是否是文件对象。例如,hasattr(obj, 'read')isinstance(inputelement, file) 相对。
为了将字符串转换为文件对象,您还可以使用这样的构造:

if not hasattr(obj, 'read'):
    obj = StringIO(str(obj))

在这段代码之后,您将能够安全地使用 obj 作为文件。

Python follows duck typing, you may check that this is file object by function that you need from object. For example hasattr(obj, 'read') against isinstance(inputelement, file).
For converting string to file objects you may also use such construction:

if not hasattr(obj, 'read'):
    obj = StringIO(str(obj))

After this code you will safely be able to use obj as a file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文