Domanda

ho visto questo nel codice di qualcuno. Che cosa 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
È stato utile?

Soluzione

L'utilizzo di questi metodi magici (__enter__, __exit__) consente di implementare gli oggetti che possono essere utilizzati facilmente con la dichiarazione with.

L'idea è che rende facile costruire codice che ha bisogno di qualche codice 'cleandown' eseguito (pensare ad esso come un blocco try-finally). Alcuni ulteriori spiegazioni qui .

Un utile esempio potrebbe essere un oggetto connessione al database (che quindi chiude automagicamente la connessione una volta che il corrispondente 'with'-economico passa nell'ambito):

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()
        ...

Come spiegato in precedenza, utilizzare questo oggetto con la dichiarazione with (potrebbe essere necessario fare from __future__ import with_statement nella parte superiore del file, se siete su Python 2.5).

with DatabaseConnection() as mydbconn:
    # do stuff

PEP343 - La 'con' dichiarazione ' ha un interessante resoconto pure.

Altri suggerimenti

Se si conosce ciò che i manager di contesto sono allora avete bisogno di niente di più per capire __enter__ e __exit__ metodi magici. Vediamo un esempio molto semplice.

In questo esempio sto aprendo miofile.txt con l'aiuto di funzione open. Il Prova / finally blocco assicura che, anche se si verifica un'eccezione imprevista miofile.txt sarà chiuso.

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

Ora sto aprendo stesso file con dichiarazione:

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

Se si guarda il codice, non ho chiudere il file e non c'è try / finally di blocco. Perché dichiarazione si chiude automaticamente miofile.txt . È anche possibile controllare chiamando attributo print(fp.closed) -. Che restituisce True

Questo è perché gli oggetti file (FP nel mio esempio) restituiti dal funzione open ha due built-in metodi __enter__ e __exit__. E 'noto anche come contesto manager. Metodo __enter__ viene chiamato all'inizio del metodo di blocco e __exit__ viene chiamato alla fine. Nota: istruzione funziona solo con oggetti che supportano il protocollo contesto mamangement cioè hanno __enter__ e __exit__ metodi. Una classe che implementa entrambi i metodi è noto come classe contesto gestore.

Ora permette di definire la nostra contesto Manager di classe.

 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")

Spero che ora avete conoscenza di base di entrambi i __enter__ e __exit__ metodi magici.

ho trovato stranamente difficile individuare la documentazione Python per __enter__ e __exit__ metodi da usare Google, in modo da aiutare gli altri ecco il link:

https://docs.python.org/ 2 / riferimento / datamodel.html # con-dichiarazione-context-manager
https://docs.python.org/3/reference /datamodel.html#with-statement-context-managers
(Particolare è la stessa per entrambe le versioni)

  

object.__enter__(self)
  Inserire il contesto di esecuzione relative a questo oggetto. La dichiarazione with legherà valore di ritorno di questo metodo per il target (s) specificato nel come clausola della dichiarazione, se del caso.

     

object.__exit__(self, exc_type, exc_value, traceback)
  Uscire dal contesto di esecuzione relative a questo oggetto. I parametri descrivono l'eccezione che ha causato il contesto può uscire. Se il contesto è stato abbandonato, senza eccezione, saranno None tutti i tre argomenti.

     

Se un'eccezione viene alimentato, e il metodo desidera sopprimere l'eccezione (ossia impedirne propagato), deve restituire un valore vero. Altrimenti, l'eccezione viene elaborato normalmente all'uscita da questo metodo.

     

Si noti che i metodi di __exit__() non dovrebbe rilanciare l'eccezione passata-in; questo è responsabilità del chiamante.

speravo in una chiara descrizione degli argomenti del metodo __exit__. Questo è carente, ma li possiamo dedurre ...

Presumibilmente exc_type è la classe di eccezione.

Si dice che non dovrebbe rilanciare l'eccezione passata-in. Questo ci suggerisce che uno degli argomenti potrebbe essere un caso di eccezione effettivo ... o forse si suppone di creare un'istanza di voi stessi dal tipo e il valore?

Possiamo rispondere, cercando in questo articolo:
http://effbot.org/zone/python-with-statement.htm

  

Ad esempio, il seguente metodo __exit__ ingoia qualsiasi TypeError, ma lascia tutte le altre eccezioni attraverso:

def __exit__(self, type, value, traceback):
    return isinstance(value, TypeError)

... così chiaramente value è un'istanza di eccezione.

E presumibilmente traceback è un traceback Python obiettare.

Oltre alle risposte di cui sopra per esemplificare ordine invocazione, un semplice esempio run

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 l'uscita:

__init__
__enter__
body
__exit__
__del__

Un promemoria: quando si utilizza la sintassi di with myclass() as mc, mc variabile ottiene il valore restituito da __enter__(), nel caso di cui sopra None! Per tale utilizzo, è necessario definire il valore di ritorno, come ad esempio:

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

prova ad aggiungere le mie risposte (il mio pensiero di apprendimento):

__enter__ e [__exit__] entrambi sono metodi che vengono richiamati in entrata e l'uscita dal corpo di " l'istruzione with " ( PEP 343 ) e l'attuazione di entrambi è chiamato contesto manager.

l'istruzione with è intenzione di nascondere il controllo del flusso di provare finalmente clausola e rendere il codice imperscrutabile.

la sintassi del con affermazione è:

with EXPR as VAR:
    BLOCK

, che si traducono in (come menzione nel 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)

provare qualche codice:

>>> 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'

ed ora cercare manualmente (segue tradurre sintassi):

>>> 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

il risultato del lato server stesso di prima

mi dispiace per il mio cattivo inglese e le mie spiegazioni poco chiare, grazie ....

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top