510 votes

À quoi sert l'instruction python "with" ?

Je suis tombé sur le Python with pour la première fois aujourd'hui. J'utilise légèrement Python depuis plusieurs mois et je ne connaissais même pas son existence ! Étant donné son statut quelque peu obscur, j'ai pensé qu'il valait la peine de poser la question :

  1. Qu'est-ce que le Python ? with déclaration est-elle destinée à être utilisée ?
  2. Qu'est-ce que à quoi sert-il ?
  3. Existe-t-il des des problèmes dont je dois être conscient, ou des des anti-modèles courants associés à son utilisation ? Y a-t-il des cas où il est préférable d'utiliser try..finally que with ?
  4. Pourquoi n'est-elle pas utilisée plus largement ?
  5. Quelles sont les classes de la bibliothèque standard qui sont compatibles avec lui ?

448voto

Tamás Points 18211
  1. Je pense que d'autres utilisateurs ont déjà répondu à cette question avant moi, aussi je ne l'ajoute que par souci d'exhaustivité : l'option with simplifie la gestion des exceptions en encapsulant les tâches communes de préparation et de nettoyage dans ce que l'on appelle la "déclaration d'exception". gestionnaires de contexte . Pour plus de détails, voir PEP 343 . Par exemple, le open est un gestionnaire de contexte en soi, qui vous permet d'ouvrir un fichier, de le garder ouvert tant que l'exécution se fait dans le contexte de l'instruction with à l'endroit où vous l'avez utilisée, et la ferme dès que vous quittez le contexte, que vous l'ayez quitté à cause d'une exception ou au cours d'un flux de contrôle normal. L'instruction with peut donc être utilisée de la même manière que l'instruction Modèle RAII en C++ : une ressource est acquise par le with et libéré lorsque vous quittez le with contexte.

  2. Quelques exemples : l'ouverture de fichiers à l'aide de with open(filename) as fp: , l'acquisition de verrous à l'aide de with lock: (où lock est une instance de threading.Lock ). Vous pouvez également construire vos propres gestionnaires de contexte à l'aide de la fonction contextmanager du décorateur de contextlib . Par exemple, j'utilise souvent cette fonction lorsque je dois changer temporairement de répertoire et revenir ensuite à l'endroit où je me trouvais :

    from contextlib import contextmanager
    import os
    
    @contextmanager
    def working_directory(path):
        current_dir = os.getcwd()
        os.chdir(path)
        try:
            yield
        finally:
            os.chdir(current_dir)
    
    with working_directory("data/stuff"):
        # do something within data/stuff
    # here I am back again in the original working directory

    Voici un autre exemple qui redirige temporairement sys.stdin , sys.stdout y sys.stderr vers un autre gestionnaire de fichier et les restaure ultérieurement :

    from contextlib import contextmanager
    import sys
    
    @contextmanager
    def redirected(**kwds):
        stream_names = ["stdin", "stdout", "stderr"]
        old_streams = {}
        try:
            for sname in stream_names:
                stream = kwds.get(sname, None)
                if stream is not None and stream != getattr(sys, sname):
                    old_streams[sname] = getattr(sys, sname)
                    setattr(sys, sname, stream)
            yield
        finally:
            for sname, stream in old_streams.iteritems():
                setattr(sys, sname, stream)
    
    with redirected(stdout=open("/tmp/log.txt", "w")):
         # these print statements will go to /tmp/log.txt
         print "Test entry 1"
         print "Test entry 2"
    # back to the normal stdout
    print "Back to normal stdout again"

    Enfin, un autre exemple qui crée un dossier temporaire et le nettoie lorsque l'on quitte le contexte :

    from tempfile import mkdtemp
    from shutil import rmtree
    
    @contextmanager
    def temporary_dir(*args, **kwds):
        name = mkdtemp(*args, **kwds)
        try:
            yield name
        finally:
            shutil.rmtree(name)
    
    with temporary_dir() as dirname:
        # do whatever you want

102voto

systempuntoout Points 27584

Je vous propose deux conférences intéressantes :

  • PEP 343 La déclaration "avec
  • Effbot Comprendre le fonctionnement de Python "avec" de Python

1. Les with est utilisée pour envelopper l'exécution d'un bloc avec des méthodes définies par un gestionnaire de contexte. Cela permet aux try...except...finally les schémas d'utilisation doivent être encapsulés en vue d'une réutilisation aisée.

2. Vous pourriez faire quelque chose comme :

with open("foo.txt") as foo_file:
    data = foo_file.read()

OU

from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
   do_something()

OR (Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
   for line in input_file:
     output_file.write(parse(line))

OU

lock = threading.Lock()
with lock:
    # Critical section of code

3. Je ne vois pas d'Antipattern ici.
Citation Plonger dans Python :

Essayez enfin, c'est bien. avec, c'est mieux.

4. Je suppose que c'est lié à l'habitude qu'ont les programmeurs d'utiliser try..catch..finally d'autres langues.

46voto

Tendayi Mawushe Points 10335

Le Python with est un support linguistique intégré de la Resource Acquisition Is Initialization couramment utilisé en C++. Il est destiné à permettre l'acquisition et la libération en toute sécurité des ressources du système d'exploitation.

Le with crée des ressources à l'intérieur d'un champ d'application/bloc. Vous écrivez votre code en utilisant les ressources du bloc. Lorsque le bloc se termine, les ressources sont proprement libérées, quel que soit le résultat du code dans le bloc (c'est-à-dire que le bloc se termine normalement ou à cause d'une exception).

De nombreuses ressources de la bibliothèque Python qui obéissent au protocole requis par la norme with et peut donc être utilisée avec elle dès le départ. Cependant, n'importe qui peut créer des ressources qui peuvent être utilisées dans une déclaration with en mettant en œuvre le protocole bien documenté : PEP 0343

Utilisez-le chaque fois que vous obtenez des ressources dans votre application qui doivent être explicitement abandonnées, telles que des fichiers, des connexions réseau, des verrous, etc.

29voto

JudoWill Points 2191

Toujours dans un souci d'exhaustivité, j'ajouterai mon cas d'utilisation le plus utile pour with déclarations.

Je fais beaucoup de calculs scientifiques et, pour certaines activités, j'ai besoin de la Decimal pour les calculs de précision arbitraire. Certaines parties de mon code ont besoin d'une grande précision et la plupart des autres parties ont besoin d'une précision moindre.

Je règle ma précision par défaut sur un nombre faible, puis j'utilise with pour obtenir une réponse plus précise pour certaines sections :

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

Je l'utilise souvent pour le test hypergéométrique, qui nécessite la division de grands nombres pour former des factoriels. Lorsque vous effectuez des calculs à l'échelle génomique, vous devez faire attention aux erreurs d'arrondi et de dépassement de capacité.

28voto

gnibbler Points 103484

Un exemple d'anti-modèle pourrait être l'utilisation de l'option with à l'intérieur d'une boucle alors qu'il serait plus efficace d'utiliser la fonction with en dehors de la boucle

par exemple

for row in lines:
    with open("outfile","a") as f:
        f.write(row)

vs

with open("outfile","a") as f:
    for row in lines:
        f.write(row)

La première méthode consiste à ouvrir et à fermer le fichier pour chaque row ce qui peut entraîner des problèmes de performance par rapport à la seconde méthode qui n'ouvre et ne ferme le fichier qu'une seule fois.

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