Резюме:
Существует множество функций, для которых было бы очень полезно иметь возможность передавать два типа объектов: объект, представляющий путь (обычно строку), и объект, представляющий какой-то поток (например, часто что-то происходит от IOBase
, но не всегда). Как это разнообразие функций может различаться между этими двумя видами объектов, чтобы их можно было обрабатывать надлежащим образом?
Скажем, у меня есть функция, предназначенная для записи файла из какого-то метода генератора объектных файлов:
spiff = MySpiffy()
def spiffy_file_makerA(spiffy_obj, file):
file_str = '\n'.join(spiffy_obj.gen_file())
file.write(file_str)
with open('spiff.out', 'x') as f:
spiffy_file_makerA(spiff, f)
...do other stuff with f...
Это работает. Ура. Но я бы предпочел не беспокоиться о том, чтобы сначала открывать файл или передавать потоки, по крайней мере иногда... поэтому я реорганизую возможность использовать путь к файлу, подобный объекту, вместо файла, подобного объекту, и return
:
def spiffy_file_makerB(spiffy_obj, file, mode):
file_str = '\n'.join(spiffy_obj.gen_file())
file = open(file, mode)
file.write(file_str)
return file
with spiffy_file_makerB(spiff, 'file.out', 'x') as f:
...do other stuff with f...
Но теперь я понимаю, что было бы полезно иметь третью функцию, которая объединяет две другие версии в зависимости от того, является ли file
файлом или файловым путем, но возвращает файл назначения f, например объект, контекстный менеджер. Чтобы я мог писать код следующим образом:
with spiffy_file_makerAB(spiffy_obj, file_path_like, mode = 'x') as f:
...do other stuff with f...
... но также вот так:
file_like_obj = get_some_socket_or_stream()
with spiffy_file_makerAB(spiffy_obj, file_like_obj, mode = 'x'):
...do other stuff with file_like_obj...
# file_like_obj stream closes when context manager exits
# unless `closefd=False`
Обратите внимание, что это потребует чего-то немного другого, чем приведенные выше упрощенные версии.
Попробуйте, как я мог бы, я не смог найти очевидный способ сделать это, и найденные мной способы казались довольно надуманными и просто потенциальными проблемами позже. Например:
def spiffy_file_makerAB(spiffy_obj, file, mode, *, closefd=True):
try:
# file-like (use the file descriptor to open)
result_f = open(file.fileno(), mode, closefd=closefd)
except TypeError:
# file-path-like
result_f = open(file, mode)
finally:
file_str = '\n'.join(spiffy_obj.gen_file())
result_f.write(file_str)
return result_f
Есть ли какие-либо предложения для лучшего способа? Неужели я так далеко от базы и должен заниматься этим совершенно по-другому?