StringIO и совместимость с оператором 'with' (менеджер контекста)
У меня есть унаследованный код с унаследованной функцией, которая принимает имя файла в качестве аргумента и обрабатывает содержимое файла. Ниже приведен рабочий факсимильный код.
То, что я хочу сделать, - это не писать на диск с некоторым контентом, который я генерирую, чтобы использовать эту устаревшую функцию, поэтому я мог бы использовать StringIO
для создания объекта вместо физического имени файла. Однако это не работает, как вы можете видеть ниже.
Я думал, что StringIO
- это способ пойти с этим. Может ли кто-нибудь сказать мне, есть ли способ использовать эту унаследованную функцию и передать ей что-то в аргументе, который не является файлом на диске, но может быть рассмотрен как функция устаревшей функции? Унаследованная функция имеет диспетчер контекста with
, выполняющий работу с параметром filename
.
Единственное, с чем я столкнулся в google, было: http://bugs.python.org/issue1286, но это меня не помогло...
код
from pprint import pprint
import StringIO
# Legacy Function
def processFile(filename):
with open(filename, 'r') as fh:
return fh.readlines()
# This works
print 'This is the output of FileOnDisk.txt'
pprint(processFile('c:/temp/FileOnDisk.txt'))
print
# This fails
plink_data = StringIO.StringIO('StringIO data.')
print 'This is the error.'
pprint(processFile(plink_data))
Выход
Это результат в FileOnDisk.txt
:
['This file is on disk.\n']
Это ошибка:
Traceback (most recent call last):
File "C:\temp\test.py", line 20, in <module>
pprint(processFile(plink_data))
File "C:\temp\test.py", line 6, in processFile
with open(filename, 'r') as fh:
TypeError: coercing to Unicode: need string or buffer, instance found
Ответы
Ответ 1
A StringIO
экземпляр уже открыт. С другой стороны, команда open
принимает только имена файлов, чтобы вернуть открытый файл. Экземпляр StringIO
не подходит в качестве имени файла.
Кроме того, вам не нужно закрывать экземпляр StringIO
, поэтому нет необходимости использовать его в качестве менеджера контекста.
Если ваш старый код может принимать имя файла, то экземпляр StringIO
не подходит. Используйте tempfile
module для создания временного имени файла.
Вот пример использования contextmanager для обеспечения последующего очистки файла temp:
import os
import tempfile
from contextlib import contextmanager
@contextmanager
def tempinput(data):
temp = tempfile.NamedTemporaryFile(delete=False)
temp.write(data)
temp.close()
try:
yield temp.name
finally:
os.unlink(temp.name)
with tempinput('Some data.\nSome more data.') as tempfilename:
processFile(tempfilename)
Ответ 2
вы можете определить свою собственную открытую функцию
fopen = open
def open(fname,mode):
if hasattr(fname,"readlines"): return fname
else: return fopen(fname,mode)
однако с необходимостью вызывать __exit__ после его завершения, а StringIO не имеет метода выхода...
вы можете определить пользовательский класс для использования с этим открытым
class MyStringIO:
def __init__(self,txt):
self.text = txt
def readlines(self):
return self.text.splitlines()
def __exit__(self):
pass