Recomiendo usar la with
declaración de Python para administrar los recursos que necesitan ser limpiados. El problema con el uso de una close()
declaración explícita es que debe preocuparse de que las personas se olviden de llamarlo o se olviden de colocarlo en un finally
bloque para evitar una pérdida de recursos cuando se produce una excepción.
Para usar la with
instrucción, cree una clase con los siguientes métodos:
def __enter__(self)
def __exit__(self, exc_type, exc_value, traceback)
En su ejemplo anterior, usaría
class Package:
def __init__(self):
self.files = []
def __enter__(self):
return self
# ...
def __exit__(self, exc_type, exc_value, traceback):
for file in self.files:
os.unlink(file)
Luego, cuando alguien quisiera usar tu clase, haría lo siguiente:
with Package() as package_obj:
# use package_obj
La variable package_obj será una instancia de tipo Package (es el valor devuelto por el __enter__
método). Se __exit__
llamará automáticamente a su método, independientemente de si se produce o no una excepción.
Incluso podría llevar este enfoque un paso más allá. En el ejemplo anterior, alguien aún podría crear una instancia de Package usando su constructor sin usar la with
cláusula. No quieres que eso suceda. Puede solucionar esto creando una clase PackageResource que defina los métodos __enter__
y __exit__
. Luego, la clase Package se definiría estrictamente dentro del __enter__
método y se devolvería. De esa manera, la persona que llama nunca podría crear una instancia de la clase Package sin usar una with
declaración:
class PackageResource:
def __enter__(self):
class Package:
...
self.package_obj = Package()
return self.package_obj
def __exit__(self, exc_type, exc_value, traceback):
self.package_obj.cleanup()
Usarías esto de la siguiente manera:
with PackageResource() as package_obj:
# use package_obj
__del__
qué no debe usarse como contraparte de__init__
. (Es decir, no es un "destructor" en el sentido de que__init__
es un constructor.