Подтвердить что ты не робот

Как принимать имена файлов и файловые объекты в функциях Python?

В моем коде у меня есть функция 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) способ принять файловый объект или строку в функцию, которая выполняет чтение текста?

4b9b3361

Ответ 1

Не принимать файлы и строки. Если вы собираетесь принимать файловые объекты, значит, вы не будете проверять тип, просто вызовите необходимые методы для фактического параметра (read, write и т.д.). Если вы собираетесь принимать строки, то вы получите файлы open -ing, что означает, что вы не сможете издеваться над параметрами. Поэтому я бы сказал, что принимаю файлы, пусть вызывающий передаёт вам файл-подобный объект и не проверяет тип.

Ответ 2

Один из способов иметь либо имя файла, либо файл-подобный объект в качестве аргумента - это реализация диспетчера контекстов который может обрабатывать оба. Реализация может быть найдена здесь, я цитирую для самостоятельного ответа:

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

Ответ 3

Python следует печатать на утке, вы можете проверить, что это объект файл по функции, которая вам нужна из объекта. Например hasattr(obj, 'read') против isinstance(inputelement, file). Для преобразования строки в файловые объекты вы также можете использовать такую ​​конструкцию:

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

После этого кода вы сможете использовать obj как файл.