Pregunta

vi esto en el código de otra. ¿Qué significa?

    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
¿Fue útil?

Solución

El uso de estos métodos mágicos (__enter__, __exit__) le permite implementar los objetos que se pueden utilizar fácilmente con la declaración with.

La idea es que hace que sea fácil de código de construcción que necesita algo de código 'cleandown' ejecutados (pensar en él como un bloque try-finally). Algunos más explicación aquí .

Un ejemplo útil podría ser un objeto de conexión de base de datos (que a continuación se cierra automágicamente la conexión una vez que el 'with'-declaración correspondiente sale del ámbito):

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, utilice este objeto con la declaración with (puede que tenga que hacer from __future__ import with_statement en la parte superior del archivo, si estás en Python 2.5).

with DatabaseConnection() as mydbconn:
    # do stuff

PEP343 - La 'con' sentencia ' tiene una valoración crítica agradable también.

Otros consejos

Si usted sabe lo que los gerentes Contexto son entonces necesita nada más para comprender los métodos __enter__ y mágicos __exit__. Vamos a ver un ejemplo muy sencillo.

En este ejemplo estoy apertura miarchivo.txt con ayuda de función de apertura. La try / finally asegura de bloques que incluso si se produce una excepción inesperada miarchivo.txt será cerrado.

fp=open(r"C:\Users\SharpEl\Desktop\myfile.txt")
try:
    for line in fp:
        print(line)
finally:
    fp.close()

Ahora estoy abriendo mismo archivo con declaración:

with open(r"C:\Users\SharpEl\Desktop\myfile.txt") as fp:
    for line in fp:
        print(line) 

Si nos fijamos en el código, que no se cerró el archivo y no hay try / finally bloque. Debido a declaración se cierra automáticamente miarchivo.txt . Incluso puede comprobarlo llamando atributo print(fp.closed) -. True que devuelve

Esto es porque el archivo de objetos (fp en mi ejemplo) devuelto por Función abierto tiene dos métodos incorporados __enter__ y __exit__. También se conoce como gestor de contexto. __enter__ método se llama en el inicio de método de bloques y __exit__ se llama al final. Nota: declaración sólo funciona con objetos que soportan el protocolo contexto mamangement es decir, que tienen métodos __enter__ y __exit__. Una clase que implementan ambos métodos se conoce como clase gestor de contexto.

Ahora vamos a definir nuestra propia gestor de contexto clase.

 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 usted tiene conocimiento básico de los dos métodos mágicos __enter__ y __exit__.

Me pareció extrañamente difícil localizar la documentación de Python para __enter__ y métodos __exit__ buscando en Google, por lo que ayudar a los demás aquí está el enlace:

https://docs.python.org/ 2 / referencia / datamodel.html #-con-declaración de contexto-gerentes
https://docs.python.org/3/reference /datamodel.html#with-statement-context-managers
(Detalle es el mismo para ambas versiones)

  

object.__enter__(self)
  Introducir el contexto de ejecución relacionados con este objeto. La declaración with se unirá valor de retorno de este método para el objetivo (s) especificada en la cláusula as de la declaración, en su caso.

     

object.__exit__(self, exc_type, exc_value, traceback)
  Salir del contexto de ejecución relacionados con este objeto. Los parámetros describen la excepción que causó el contexto que se cierra. Si el contexto se salió sin excepción, los tres argumentos serán None.

     

Si se suministra una excepción, y el método desea para suprimir la excepción (es decir, evitar que sea propagada), debe devolver un valor verdadero. De lo contrario, la excepción será procesada normalmente a la salida de este método.

     

Tenga en cuenta que los métodos __exit__() no deben volver a subir el pasado en la excepción; esto es responsabilidad de la persona que llama.

Me esperaba una descripción clara de los argumentos del método __exit__. Esto no se da, pero podemos deducir de ellos ...

Es de suponer que exc_type es la clase de la excepción.

Se dice que no se debe volver a subir la excepción pasado-in. Esto nos sugiere que uno de los argumentos podría ser un caso de excepción real ... o tal vez que se supone que es una instancia de sí mismo de tipo y valor?

puede responder examinado este artículo:
http://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 value es una instancia de excepción.

Y presumiblemente traceback es un pitón rastreo objeto.

Además de las respuestas anteriores para ejemplificar fin invocación, un simple ejemplo de ejecución

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, mc variable obtiene el valor devuelto por __enter__(), en el caso None arriba! Para tal uso, necesidad de definir el valor de retorno, como por ejemplo:

def __enter__(self): 
    print('__enter__')
    return self

trate de añadir mis respuestas (mi idea de aprendizaje):

__enter__ y [__exit__] ambos son métodos que se invocan en la entrada y salida del cuerpo de " la sentencia with " ( PEP 343 ) y la aplicación de ambos se llama gestor de contexto.

con la declaración es la intención de control de flujo de ocultación de intentarlo, finalmente cláusula y hacer que el código inescrutable.

la sintaxis de la sentencia with es:

with EXPR as VAR:
    BLOCK

que se traducen a (como se menciona en PEP 343):

mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

probar un poco de código:

>>> import logging
>>> import socket
>>> import sys

#server socket on another terminal / python interpreter
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.listen(5)
>>> s.bind((socket.gethostname(), 999))
>>> while True:
>>>    (clientsocket, addr) = s.accept()
>>>    print('get connection from %r' % addr[0])
>>>    msg = clientsocket.recv(1024)
>>>    print('received %r' % msg)
>>>    clientsocket.send(b'connected')
>>>    continue

#the client side
>>> class MyConnectionManager:
>>>     def __init__(self, sock, addrs):
>>>         logging.basicConfig(level=logging.DEBUG, format='%(asctime)s \
>>>         : %(levelname)s --> %(message)s')
>>>         logging.info('Initiating My connection')
>>>         self.sock = sock
>>>         self.addrs = addrs
>>>     def __enter__(self):
>>>         try:
>>>             self.sock.connect(addrs)
>>>             logging.info('connection success')
>>>             return self.sock
>>>         except:
>>>             logging.warning('Connection refused')
>>>             raise
>>>     def __exit__(self, type, value, tb):
>>>             logging.info('CM suppress exception')
>>>             return False
>>> addrs = (socket.gethostname())
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> with MyConnectionManager(s, addrs) as CM:
>>>     try:
>>>         CM.send(b'establishing connection')
>>>         msg = CM.recv(1024)
>>>         print(msg)
>>>     except:
>>>         raise
#will result (client side) :
2018-12-18 14:44:05,863         : INFO --> Initiating My connection
2018-12-18 14:44:05,863         : INFO --> connection success
b'connected'
2018-12-18 14:44:05,864         : INFO --> CM suppress exception

#result of server side
get connection from '127.0.0.1'
received b'establishing connection'

y ahora tratar de forma manual (después de traducir la sintaxis):

>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #make new socket object
>>> mgr = MyConnection(s, addrs)
2018-12-18 14:53:19,331         : INFO --> Initiating My connection
>>> ext = mgr.__exit__
>>> value = mgr.__enter__()
2018-12-18 14:55:55,491         : INFO --> connection success
>>> exc = True
>>> try:
>>>     try:
>>>         VAR = value
>>>         VAR.send(b'establishing connection')
>>>         msg = VAR.recv(1024)
>>>         print(msg)
>>>     except:
>>>         exc = False
>>>         if not ext(*sys.exc_info()):
>>>             raise
>>> finally:
>>>     if exc:
>>>         ext(None, None, None)
#the result:
b'connected'
2018-12-18 15:01:54,208         : INFO --> CM suppress exception

el resultado de la del lado del servidor igual que antes

lo siento por mi mala Inglés y mis explicaciones poco claras, gracias ....

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top