2012-08-09 12 views
32

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.StringIO y compatibilidad con la instrucción 'with' (administrador de contexto)

Lo que quiero hacer no es 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 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 administrador de contexto with trabajando en el valor del parámetro filename.

La única cosa que me encontré en Google era: http://bugs.python.org/issue1286, pero eso no me ayuda ...

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 salida 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 
+3

usted no puede una instancia Stringio –

Respuesta

52

A StringIO instancia es un archivo abierto ya. El comando open, por otro lado, solo toma los nombres de archivo, para devolver un archivo abierto. Una instancia StringIO no es adecuada como nombre de archivo.

Además, no necesita cerrar una instancia de StringIO, por lo que tampoco es necesario utilizarla como gestor de contexto.

Si todo el código heredado puede tomar es un nombre de archivo, entonces una instancia StringIO no es el camino a seguir. Use el tempfile module para generar un nombre de archivo temporal en su lugar.

Aquí hay un ejemplo usando un ContextManager para asegurar el archivo temporal se limpia 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) 
+0

Estoy usando esta solución. Aquí hay un enlace al código de muestra que implementa esto directamente: http://pastie.org/4450354. ¡Gracias a todos los que contribuyeron aquí! – mpettis

+2

@mpettis: actualicé mi respuesta para dar un ejemplo usando un administrador de contexto que creará el archivo temporal y lo limpiará de una sola vez. –

+0

Esa es realmente una manera elegante de manejar esto ... ¡Gracias! – mpettis

4

se podría definir su propia función abierta embargo

fopen = open 
def open(fname,mode): 
    if hasattr(fname,"readlines"): return fname 
    else: return fopen(fname,mode) 

con quiere llamar __exit__ después de su hecho y StringIO no tiene un método de salida ...

se podría definir una clase personalizada para usar con esta abierta

class MyStringIO: 
    def __init__(self,txt): 
     self.text = txt 
    def readlines(self): 
      return self.text.splitlines() 
    def __exit__(self): 
      pass 
+0

Por desgracia, eso no resuelve el problema, ya que tendría que estar dentro "abierto" de la función heredada – jdi

+0

¿no podría esta opción anularla mientras esté en el mismo archivo? –

+0

@jdi Creo que podría funcionar si se definió antes de la función heredada, es decir, cuando se importa el módulo heredado. –

Cuestiones relacionadas