examples - Explicando ''__enter__'' y ''__exit__'' de Python
plot python 3 (4)
Vi esto en el código de alguien. Qué significa eso?
def __enter__(self):
return self
def __exit__(self, type, value, tb):
self.stream.close()
from __future__ import with_statement#for python2.5
class a(object):
def __enter__(self):
print ''sss''
return ''sss111''
def __exit__(self ,type, value, traceback):
print ''ok''
return False
with a() as s:
print s
print s
Además de las respuestas anteriores para ejemplificar el orden de invocación, un ejemplo de ejecución simple
class myclass:
def __init__(self):
print("__init__")
def __enter__(self):
print("__enter__")
def __exit__(self, type, value, traceback):
print("__exit__")
def __del__(self):
print("__del__")
with myclass():
print("body")
Produce la salida:
__init__
__enter__
body
__exit__
__del__
Un recordatorio: cuando se utiliza la sintaxis with myclass() as mc
, la variable mc obtiene el valor devuelto por __enter__()
, en el caso anterior ¡ None
! Para tal uso, es necesario definir el valor de retorno, como:
def __enter__(self):
print(''__enter__'')
return self
El uso de estos métodos mágicos ( __enter__
, __exit__
) le permite implementar objetos que se pueden usar fácilmente con la instrucción with
.
La idea es que facilita la creación de código que necesita un código de ''limpieza'' ejecutado (considérelo como un bloque try-finally
). effbot.org/zone/python-with-statement.htm .
Un ejemplo útil podría ser un objeto de conexión de base de datos (que luego cierra automáticamente la conexión una vez que la declaración ''with'' correspondiente se sale del alcance):
class DatabaseConnection(object):
def __enter__(self):
# make a database connection and return it
...
return self.dbconn
def __exit__(self, exc_type, exc_val, exc_tb):
# make sure the dbconnection gets closed
self.dbconn.close()
...
Como se explicó anteriormente, use este objeto con la instrucción with
(es posible que tenga que hacerlo from __future__ import with_statement
en la parte superior del archivo si está en Python 2.5).
with DatabaseConnection() as mydbconn:
# do stuff
PEP343 - El ''con'' declaración ''también tiene una buena reseña.
Me resultó extrañamente difícil localizar los documentos de Python para los métodos __enter__
y __exit__
de Google, así que para ayudar a otros aquí está el enlace:
https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers
object.__enter__(self)
Ingrese el contexto de tiempo de ejecución relacionado con este objeto. La declaraciónwith
vinculará el valor de retorno de este método al objetivo (s) especificado en la cláusula as de la declaración, si la hubiera.
object.__exit__(self, exc_type, exc_value, traceback)
Salga del contexto de tiempo de ejecución relacionado con este objeto. Los parámetros describen la excepción que causó que se salga el contexto. Si se salió del contexto sin una excepción, los tres argumentos seránNone
.Si se proporciona una excepción, y el método desea suprimir la excepción (es decir, evitar que se propague), debe devolver un valor verdadero. De lo contrario, la excepción se procesará normalmente al salir de este método.
Tenga en cuenta que los
__exit__()
no deben__exit__()
excepción pasada; esta es la responsabilidad del que llama.
Esperaba una descripción clara de los argumentos del método __exit__
. Esto falta pero podemos deducirlos ...
Presumiblemente, exc_type
es la clase de la excepción.
Dice que no debe volver a elevar la excepción pasada. Esto nos sugiere que uno de los argumentos podría ser una instancia de Excepción real ... ¿o quizás se supone que debe crear una instancia del mismo tipo y valor?
Podemos responder mirando este artículo:
effbot.org/zone/python-with-statement.htm
Por ejemplo, el siguiente método
__exit__
traga cualquier TypeError, pero permite todas las demás excepciones a través de:
def __exit__(self, type, value, traceback):
return isinstance(value, TypeError)
... tan claramente el value
es una instancia de excepción.
Y presumiblemente, el traceback
es un objeto de traceback Python.
Si sabe qué son los gestores de contexto, entonces no necesita nada más para entender los métodos mágicos __enter__
y __exit__
. Veamos un ejemplo muy simple.
En este ejemplo, estoy abriendo myfile.txt con la ayuda de la función de apertura . El bloque try / finally garantiza que incluso si ocurre una excepción inesperada, myfile.txt se cerrará.
fp=open(r"C:/Users/SharpEl/Desktop/myfile.txt")
try:
for line in fp:
print(line)
finally:
fp.close()
Ahora estoy abriendo el mismo archivo con la declaración:
with open(r"C:/Users/SharpEl/Desktop/myfile.txt") as fp:
for line in fp:
print(line)
Si observa el código, no cerré el archivo y no hay un bloque try / finally . Porque con la sentencia se cierra automáticamente myfile.txt . Incluso puede verificarlo llamando al atributo print(fp.closed)
, que devuelve True
.
Esto se debe a que los objetos de archivo (fp en mi ejemplo) devueltos por la función open tienen dos métodos __enter__
y __exit__
. También se conoce como gestor de contexto. __enter__
método __enter__
se llama al principio con bloque y el método __exit__
se llama al final. Nota: con la declaración solo funciona con objetos que admiten el protocolo de cambio de contexto, es decir, tienen los métodos __enter__
y __exit__
. Una clase que implementa ambos métodos se conoce como clase de administrador de contexto.
Ahora vamos a definir nuestra propia clase de administrador de contexto .
class Log:
def __init__(self,filename):
self.filename=filename
self.fp=None
def logging(self,text):
self.fp.write(text+''/n'')
def __enter__(self):
print("__enter__")
self.fp=open(self.filename,"a+")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("__exit__")
self.fp.close()
with Log(r"C:/Users/SharpEl/Desktop/myfile.txt") as logfile:
print("Main")
logfile.logging("Test1")
logfile.logging("Test2")
Espero que ahora tengas un entendimiento básico de los métodos mágicos __enter__
y __exit__
.