2011-12-20 6 views
9

Tengo una clase que ajusta algunas funcionalidades de manejo de archivos que necesito. Otra clase crea una instancia del filehandler y la usa durante un tiempo indeterminado. Eventualmente, se destruye el caller, lo que destruye la única referencia al filehandler.Contenedor de clase alrededor del archivo: forma correcta de cerrar el identificador del archivo cuando ya no se hace referencia a él

¿Cuál es la mejor manera de tener el filehandler cerca del archivo?

Actualmente uso __del__(self) pero después de ver severaldifferentquestionsand articles, estoy bajo la impresión de que esto se considera una mala cosa .

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __del__(self): 
     self.thefile.close() 

Esa es la parte relevante del controlador. El objetivo de la clase es abstraer los detalles del trabajo con el objeto de archivo subyacente y también evitar leer todo el archivo en la memoria innecesariamente. Sin embargo, parte del manejo del archivo subyacente es cerrarlo cuando el objeto se sale del alcance.

Se supone que el caller no conoce o no le importan los detalles del filehandler. Es el trabajo de filehandler liberar todos los recursos necesarios cuando se sale del alcance. Esa es una de las razones por las que fue abstraída en primer lugar. Por lo tanto, parece que tengo que mover el código filehandler al objeto que llama o tratar con una abstracción con goteras.

¿Pensamientos?

Respuesta

11

__del__ no es, en sí mismo, algo malo. Solo debe tener mucho cuidado para no crear ciclos de referencia en objetos que tienen definido __del__. Si encuentra que necesita crear ciclos (parent se refiere a child que se refiere a parent) entonces querrá usar el módulo weakref.

Por lo tanto, __del__ está bien, tenga cuidado con las referencias cíclicas.

La recolección de basura: El punto importante aquí es que cuando un objeto sale del ámbito, se puede recolección de datos innecesarios, y de hecho, se ser recolector de basura ... pero cuando? No hay garantía sobre cuándo y diferentes implementaciones de Python tienen diferentes características en esta área. Por lo tanto, para administrar recursos, es mejor que sea explícito y agregue .close() en su filehandler o, si su uso es compatible, agregue los métodos __enter__ y __exit__.

El __enter__ and __exit__ methods se describen aquí. Una cosa muy buena de ellos es que se llama al __exit__ incluso cuando se producen excepciones, por lo que puede contar o cerrar con gracia sus recursos.

Su código, mejorado para __enter__/__exit__:

class fileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefilename = dbf 
    def __enter__(self): 
     self.thefile = open(self.thefilename, 'rb') 
     return self 
    def __exit__(self, *args): 
     self.thefile.close() 

Tenga en cuenta que el archivo se abre en vez de __enter____init__ - esto le permite crear el objeto FileHandler una vez, y luego usarlo cuando necesitar en un with sin volver a crearlo:

fh = filehandler('some_dbf') 
with fh: 
    #file is now opened 
    #do some stuff 
#file is now closed 
#blah blah 
#need the file again, so 
with fh: 
    # file is open again, do some stuff with it 
#etc, etc 
+0

buen truco con abrir el archivo en '__ __enter()' - también se puede hacer un poco de magia allí para retener la posición del archivo entre abre/cierra. – kindall

+1

Muy bien, esto está mucho más cerca de lo que quería. Los ciclos de ref son lo primero que revisé, y no tengo ninguno. Pero algunos artículos dicen que las cadenas de objetos completas no se podrán recoger si un objeto hoja tiene un método del del, independientemente de los ciclos de ref. –

+0

@SpencerRathbun: toda la documentación que he podido encontrar indica que los artículos son incobrables ** solo si ** hay ciclos de ref. –

6

Como lo ha escrito, la clase no cierra el archivo de forma más fiable. Si simplemente deja caer la instancia del administrador de archivos en el piso, entonces el archivo no se cerrará hasta que el objeto se destruya. Esto podría ser inmediatamente o no serlo hasta que el objeto sea basura recolectada, pero al dejar caer un objeto de archivo simple en el suelo se cerraría con la misma rapidez. Si la única referencia a thefile es desde dentro de su objeto de clase, cuando filehandler es basura recogida thefile también se recogerá la basura y, por lo tanto, se cerrará al mismo tiempo.

La forma correcta de utilizar archivos es utilizar el with declaración:

with open(dbf, 'rb') as thefile: 
    do_something_with(thefile) 

que garantice que thefile está siempre cerrada siempre las salidas with cláusula. Si desea envolver su archivo dentro de otro objeto que pueda hacer eso también mediante la definición de __enter__ y __exit__ métodos:

class FileHandler: 
    def __init__(self, dbf): 
     self.logger = logging.getLogger('fileHandler') 
     self.thefile = open(dbf, 'rb') 
    def __enter__(self): 
     return self 
    def __exit__(self): 
     self.thefile.close() 

y entonces usted puede hacer:

with FileHandler(dbf) as fh: 
    do_something_with(fh) 

y estar seguro de que el archivo se cierra rápidamente .

Cuestiones relacionadas