web-dev-qa-db-fra.com

Comment écrire un gestionnaire de contexte null (no-op) en Python?

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

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 .

36
Julian

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.

3
Martin Valgur

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

  • Vous voulez probablement ajouter un # no-op commentaire.
1
Huazuo Gao