una txt partir modos lista linea leer importar guardar especifica espaƱol datos crear como binarios archivos archivo apertura python python-3.x

txt - python guardar datos



Subclasificar objetos de archivo(para extender las operaciones de apertura y cierre) en Python 3 (3)

Supongamos que quiero extender la abstracción de archivos incorporada con operaciones adicionales en tiempo de open y close . En Python 2.7 esto funciona:

class ExtFile(file): def __init__(self, *args): file.__init__(self, *args) # extra stuff here def close(self): file.close(self) # extra stuff here

Ahora estoy buscando actualizar el programa a Python 3, en el que open es una función de fábrica que podría devolver una instancia de cualquiera de varias clases diferentes del módulo io según cómo se llame. Podría, en principio, subclasificarlos a todos, pero eso es tedioso, y tendría que volver a implementar el envío que hace open . (En Python 3, la distinción entre archivos binarios y de texto es bastante más importante que en 2.x, y necesito ambos). Estos objetos se pasarán al código de la biblioteca que podría hacer casi cualquier cosa con ellos, por lo que el idioma de hacer una clase de tipo pato "similar a un archivo" que envuelva el valor de retorno de open métodos open y reenviados será más detallado.

¿Alguien puede sugerir un enfoque 3.x que involucre la menor cantidad de información adicional posible más allá del código 2.x mostrado?


Puedes usar un administrador de contexto. Por ejemplo este:

class SpecialFileOpener: def __init__ (self, fileName, someOtherParameter): self.f = open(fileName) # do more stuff print(someOtherParameter) def __enter__ (self): return self.f def __exit__ (self, exc_type, exc_value, traceback): self.f.close() # do more stuff print(''Everything is over.'')

Entonces puedes usarlo así:

>>> with SpecialFileOpener(''C://test.txt'', ''Hello world!'') as f: print(f.read()) Hello world! foo bar Everything is over.

Usar un bloque de contexto with es preferible para objetos de archivo (y otros recursos) de todos modos.


Tuve un problema similar, y el requisito de ser compatible con Python 2.xy 3.x. Lo que hice fue similar al siguiente ( versión completa actual ):

class _file_obj(object): """Check if `f` is a file name and open the file in `mode`. A context manager.""" def __init__(self, f, mode): if isinstance(f, str): self.file = open(f, mode) else: self.file = f self.close_file = (self.file is not f) def __enter__(self): return self def __exit__(self, *args, **kwargs): if (not self.close_file): return # do nothing # clean up exit = getattr(self.file, ''__exit__'', None) if exit is not None: return exit(*args, **kwargs) else: exit = getattr(self.file, ''close'', None) if exit is not None: exit() def __getattr__(self, attr): return getattr(self.file, attr) def __iter__(self): return iter(self.file)

Pasa todas las llamadas a los objetos de archivo subyacentes y puede inicializarse desde un archivo abierto o desde un nombre de archivo. También funciona como gestor de contexto. Inspirado por esta respuesta .


tl; dr Usa un administrador de contexto. Vea al final de esta respuesta las precauciones importantes sobre ellos.

Los archivos se complicaron más en Python 3. Si bien hay algunos métodos que se pueden usar en las clases de usuarios normales, esos métodos no funcionan con las clases integradas. Una forma es mezclar una clase deseada antes de crear una instancia, pero esto requiere saber cuál debe ser la primera clase de mezcla:

class MyFileType(???): def __init__(...) # stuff here def close(self): # more stuff here

Debido a que hay muchos tipos, y es posible que se agreguen más en el futuro (poco probable, pero posible), y no sabemos con certeza cuál se devolverá hasta después de la open la llamada, este método no funciona.

Otro método es cambiar nuestro tipo personalizado para que tenga el archivo devuelto ___bases__ , y modificar el atributo __class__ la instancia __class__ a nuestro tipo personalizado:

class MyFileType: def close(self): # stuff here some_file = open(path_to_file, ''...'') # ... = desired options MyFileType.__bases__ = (some_file.__class__,) + MyFile.__bases__

pero esto rinde

Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __bases__ assignment: ''_io.TextIOWrapper'' deallocator differs from ''object''

Otro método más que podría funcionar con clases de usuario puro es crear el tipo de archivo personalizado sobre la marcha, directamente desde la clase de la instancia devuelta, y luego actualizar la clase de la instancia devuelta:

some_file = open(path_to_file, ''...'') # ... = desired options class MyFile(some_file.__class__): def close(self): super().close() print("that''s all, folks!") some_file.__class__ = MyFile

pero otra vez:

Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __class__ assignment: only for heap types

Entonces, parece que el mejor método que funcionará en Python 3, y afortunadamente también funcionará en Python 2 (útil si quiere que la misma base de código funcione en ambas versiones) es tener un administrador de contexto personalizado:

class Open(object): def __init__(self, *args, **kwds): # do custom stuff here self.args = args self.kwds = kwds def __enter__(self): # or do custom stuff here :) self.file_obj = open(*self.args, **self.kwds) # return actual file object so we don''t have to worry # about proxying return self.file_obj def __exit__(self, *args): # and still more custom stuff here self.file_obj.close() # or here

y para usarlo:

with Open(''some_file'') as data: # custom stuff just happened for line in data: print(line) # data is now closed, and more custom stuff # just happened

Un punto importante a tener en cuenta: cualquier excepción no controlada en __init__ o __enter__ evitará que __exit__ ejecute, por lo que en esas dos ubicaciones aún debe usar la función try / except y / o try / finally para asegurarse de que no haya fugas. recursos