325 votes

python: crée un bloc "avec" sur plusieurs gestionnaires de contexte

Supposons que vous disposez de trois objets que vous acquérir via le gestionnaire de contexte, par exemple Une serrure, d'une base et d'un socket ip. Vous pouvez les acquérir par:

with lock:
   with db_con:
       with socket:
            #do stuff

Mais est-il un moyen de le faire en un seul bloc? quelque chose comme

with lock,db_con,socket:
   #do stuff

En outre, est-il possible, étant donné un tableau de longueur inconnue des objets qui ont contexte, les gestionnaires, est-il possible de faire en quelque sorte à faire:

a=[lock1, lock2, lock3, db_con1, socket, db_con2]
with a as res:
    #now all objects in array are acquired

Si la réponse est "non", est-ce parce que le besoin d'une telle fonctionnalité implique une mauvaise conception, ou peut-être que je devrais suggérer dans une ppe? :-P

546voto

interjay Points 51000

Dans la version 2.6 de Python et ci-dessous, vous pouvez utiliser contextlib.nested:

from contextlib import nested

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

est équivalent à:

m1, m2, m3 = A(), B(), C()
with m1 as X:
    with m2 as Y:
        with m3 as Z:
            do_something()

Notez que ce n'est pas exactement la même que normalement à l'aide de imbriquée withcar A(), B(), et C() seront tous appelés d'abord, avant d'entrer dans le cadre des gestionnaires. Cela ne fonctionnera pas correctement si l'une de ces fonctions peuvent lever des exceptions, mais les travaux pour les exemples de la question.

En Python 2.7 et 3.1, la syntaxe a été ajoutée, et contextlib.nested a été supprimée:

with A() as X, B() as Y, C() as Z:
    do_something()

En Python 3.3, vous pouvez également entrer un inconnu-longueur de la liste des gestionnaires de contexte en utilisant contextlib.ExitStack:

with ExitStack() as stack:
    for mgr in ctx_managers:
        stack.enter_context(mgr)
    # ...

Cela vous permet de créer le contexte des gestionnaires que vous ajoutez à l' ExitStack, ce qui empêche l'éventuel problème avec contextlib.nested.

36voto

Mark Byers Points 318575

La première partie de votre question est possible dans Python 3.1 .

Avec plus d'un élément, les gestionnaires de contexte sont traités comme si plusieurs déclarations avec étaient imbriquées:

 with A() as a, B() as b:
    suite
 

est équivalent à

 with A() as a:
    with B() as b:
        suite
 

Modifié dans la version 3.1 : prise en charge de plusieurs expressions de contexte

11voto

Neil G Points 7028

La deuxième partie de votre question est résolue avec contextlib.ExitStack en Python 3.3 .

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