Parfois, j'ai besoin d'un gestionnaire de contexte factice qui ne fait rien. Il peut ensuite être utilisé comme remplaçant pour un gestionnaire de contexte plus utile, mais facultatif. Par exemple:
ctx_mgr = <meaningfulContextManager> if <condition> else <nullContextManager>
with ctx_mgr:
...
Comment définir un gestionnaire de contexte aussi trivial et vide? La bibliothèque Python en offre-t-elle une sur étagère?
Que diriez-vous des cas où nous voulons que le contexte soit utilisé avec une clause as
?
with ctx_mgr as resource:
<operations on resource>
Python 3.7 et supérieur : utilisez contextlib.nullcontext
, spécialement conçu pour cette raison.
Avant Python 3.7, la bibliothèque standard ne propose pas de gestionnaire de contexte spécialement conçu pour ces cas d'utilisation, mais il existe quelques solutions.
Puisque Python 3.4 , contextlib.suppress
peut être utilisé à cette fin dans le premier cas, c'est-à-dire lorsqu'il n'y a pas de clause as
:
ctx_mgr = <meaningfulContextManager> if <condition> else contextlib.suppress()
with ctx_mgr:
...
Depuis Python 3.3 , une solution de contournement similaire est également disponible, contextlib.ExitStack
, quoique plus lent que suppress
(cela prend deux fois plus de temps dans mes tests).
Avant Python 3.3 , ou au cas où vous auriez besoin d'un as
clause avant Python 3.7, les développeurs doivent lancer la leur. Voici une implémentation possible (voir la note en bas, mais toutes les erreurs sont les miennes)) :
class NullContextManager(object):
def __init__(self, dummy_resource=None):
self.dummy_resource = dummy_resource
def __enter__(self):
return self.dummy_resource
def __exit__(self, *args):
pass
On peut alors écrire:
ctx_mgr = <meaningfulContextManager> if <condition> else NullContextManager(dummy_resource)
with ctx_mgr as resource:
<operations on resource>
Bien entendu, dummy_resource
Devra prendre en charge toutes les opérations requises de la ressource "significative". Ainsi, par exemple, si le gestionnaire de contexte significatif, sur __enter__()
, renvoie quelque chose qui est fait à quack()
à l'intérieur du bloc géré, dummy_resource
Devra également prendre en charge cela, mais peut-être sans rien faire du tout.
class DummyDuck(object):
def quack()
# Ssssh...
pass
ctx_mgr = <meaningfulContextManager> if <condition> else NullContextManager(DummyDuck())
with ctx_mgr as someDuck:
someDuck.quack()
Source: A Python . Un grand merci à tous ceux qui ont contribué à cette discussion. C'est ma tentative de résumer ses résultats dans une question à réponse libre, à gagnez du temps en lisant ce long fil. Voir aussi Python de cette utilisation de ExitStack
.
Une solution simple pour Python 3.6 et inférieur, dont 2.7:
from contextlib import contextmanager
@contextmanager
def nullcontext(enter_result=None):
yield enter_result
Depuis Python 3.7 vous devez utiliser le contextlib.nullcontext
à la place.
Puisque Python 3.2, memoryview(b'')
peut être utilisé comme gestionnaire de contexte sans opération. Voir https://docs.python.org/3/library/ stdtypes.html # memoryview.release .
Avantages
Aucune importation requise
Fonctionne sur 3.2+
Environ deux fois plus vite que contextlib.nullcontext
Contre
# no-op
commentaire.