python - manager - StringIO y compatibilidad con la declaración ''with''(administrador de contexto)
context manager python (2)
Tengo algún código heredado con una función heredada que toma un nombre de archivo como argumento y procesa el contenido del archivo. Un facsímil de trabajo del código está debajo.
Lo que quiero hacer es no tener que escribir en el disco con algún contenido que genere para usar esta función heredada, así que pensé que podría usar StringIO
para crear un objeto en lugar del nombre de archivo físico. Sin embargo, esto no funciona, como puedes ver a continuación.
Pensé que StringIO
era el camino a seguir con esto. ¿Alguien puede decirme si hay una forma de usar esta función heredada y pasarle algo en el argumento de que no es un archivo en el disco pero que puede ser tratado como tal por la función heredada? La función heredada tiene el gestor de contexto trabajando en el valor del parámetro de filename
.
La única cosa que encontré en google fue: http://bugs.python.org/issue1286 , pero eso no me ayudó ...
Código
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))
Salida
Este es el resultado en FileOnDisk.txt
:
[''This file is on disk./n'']
Este es el error:
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
Una instancia de StringIO
es un archivo abierto ya. El comando open
, por otro lado, solo toma los nombres de archivo, para devolver un archivo abierto. Una instancia de StringIO
no es adecuada como nombre de archivo.
Además, no es necesario cerrar una instancia de StringIO
, por lo que tampoco es necesario utilizarla como gestor de contexto.
Si todo su código heredado puede tomar es un nombre de archivo, entonces una instancia de StringIO
no es el camino a seguir. Use el módulo tempfile
para generar un nombre de archivo temporal en su lugar.
Aquí hay un ejemplo que usa un gestor de contexto para asegurar que el archivo temporal se limpie después:
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)
podrías definir tu propia función abierta
fopen = open
def open(fname,mode):
if hasattr(fname,"readlines"): return fname
else: return fopen(fname,mode)
sin embargo, con quiere llamar a __exit__ una vez hecho esto y StringIO no tiene un método de salida ...
puedes definir una clase personalizada para usar con este abrir
class MyStringIO:
def __init__(self,txt):
self.text = txt
def readlines(self):
return self.text.splitlines()
def __exit__(self):
pass