440 votes

Explication des fonctions "__enter__" et "__exit__" de Python

J'ai vu ça dans le code de quelqu'un. Qu'est-ce que cela signifie ?

    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

20 votes

Une bonne explication ici : effbot.org/zone/python-with-statement.htm

7 votes

@StevenVascellaro Modifier le code d'une question est généralement une mauvaise idée, notamment lorsqu'il y a des erreurs dans le code. Cette question a été posée en pensant à Py2, et il n'y a aucune raison de la mettre à jour pour Py3.

5voto

Wira Bhakti Points 99

Essayez d'ajouter mes réponses (ma pensée d'apprentissage) :

__enter__ y [__exit__] sont des méthodes qui sont invoquées à l'entrée et à la sortie du corps de " la déclaration avec " ( PEP 343 ) et la mise en œuvre des deux est appelée gestionnaire de contexte.

L'instruction with a pour but de cacher le contrôle du flux de la clause try finally et de rendre le code impénétrable.

la syntaxe de l'instruction with est :

with EXPR as VAR:
    BLOCK

qui se traduisent par (comme mentionné dans 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)

essayez un peu de code :

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

et maintenant essayer manuellement (en suivant la syntaxe de translate) :

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

le résultat du côté serveur est le même que précédemment

désolé pour mon mauvais anglais et mes explications peu claires, merci....

2voto

Viraj Dhanushka Points 29

Appels Python __enter__ lorsque l'exécution entre dans le contexte de l'instruction with et qu'il est temps d'acquérir la ressource. Lorsque l'exécution quitte à nouveau le contexte, Python appelle __exit__ pour libérer la ressource

Examinons les gestionnaires de contexte et l'instruction "with" en Python. Le gestionnaire de contexte est un simple "protocole" (ou interface) que votre objet doit suivre pour pouvoir être utilisé avec l'instruction with. En gros, tout ce que vous devez faire, c'est ajouter entrez y quitter à un objet si vous voulez qu'il fonctionne comme un gestionnaire de contexte. Python appellera ces deux méthodes aux moments appropriés du cycle de gestion des ressources.

Voyons à quoi cela ressemblerait concrètement. Voici à quoi pourrait ressembler une implémentation simple du gestionnaire de contexte open() :

class ManagedFile:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        self.file = open(self.name, 'w')
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()

Notre classe ManagedFile suit le protocole du gestionnaire de contexte et supporte maintenant l'instruction with.

>>> with ManagedFile('hello.txt') as f:
...    f.write('hello, world!')
...    f.write('bye now')`enter code here`

Appels Python entrez lorsque l'exécution entre dans le contexte de l'instruction with et qu'il est temps d'acquérir la ressource. Lorsque l'exécution quitte à nouveau le contexte, Python appelle quitter pour libérer la ressource.

L'écriture d'un gestionnaire de contexte basé sur des classes n'est pas la seule façon de prendre en charge l'instruction with en Python. Le module utilitaire contextlib de la bibliothèque standard fournit quelques abstractions supplémentaires construites au-dessus du protocole de base du gestionnaire de contexte. Cela peut vous rendre la vie un peu plus facile si vos cas d'utilisation correspondent à ce qui est offert par contextlib.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X