Supposons que vous ayez acquis trois objets via le gestionnaire de contexte, par exemple Un verrou, une connexion à une base de données et une socket IP . Vous pouvez les acquérir de la manière suivante:
with lock:
with db_con:
with socket:
#do stuff
Mais y a-t-il un moyen de le faire en un bloc? quelque chose comme
with lock,db_con,socket:
#do stuff
De plus, est-il possible, étant donné un tableau de longueur inconnue d'objets ayant des gestionnaires de contexte, de faire en quelque sorte:
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 la nécessité d'une telle fonctionnalité implique une mauvaise conception, ou peut-être devrais-je le suggérer dans un coup de pouce? :-P
Dans Python 2.7 et 3.1 et au-dessus, vous pouvez écrire:
with A() as X, B() as Y, C() as Z:
do_something()
C'est normalement la meilleure méthode à utiliser, mais si vous avez une liste de gestionnaires de contexte de longueur inconnue, vous aurez besoin de l'une des méthodes ci-dessous.
Dans Python 3.3, vous pouvez entrer une liste de gestionnaires de contexte de longueur inconnue à l’aide de contextlib.ExitStack :
with ExitStack() as stack:
for mgr in ctx_managers:
stack.enter_context(mgr)
# ...
Cela vous permet de créer les gestionnaires de contexte à mesure que vous les ajoutez à la ExitStack
, ce qui évite le problème possible avec contextlib.nested
(mentionné ci-dessous).
contextlib2 fournit un backport de ExitStack
pour Python 2.6 et 2.7.
Dans Python 2.6 et au-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 chose que d'utiliser normalement with
imbriqué, car A()
, B()
et C()
seront tous appelés dans un premier temps avant d'entrer dans les gestionnaires de contexte. Cela ne fonctionnera pas correctement si l'une de ces fonctions déclenche une exception.
contextlib.nested
est obsolète dans les nouvelles versions de Python au profit des méthodes ci-dessus.
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
La réponse de @ interjay est correcte. Toutefois, si vous avez besoin de le faire pour les gestionnaires de contexte longs, par exemple les gestionnaires de contexte mock.patch, vous réalisez rapidement que vous souhaitez le diviser sur plusieurs lignes. Il s'avère que vous ne pouvez pas les envelopper par deux, vous devez donc utiliser des barres obliques inverses. Voici à quoi ça ressemble:
with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \
mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \
mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c:
do_something()
La deuxième partie de votre question est résolue avec contextlib.ExitStack
dans Python 3.3 .
Suite à la réponse de @ sage88, vous pouvez toujours affecter à ces correctifs des noms de variables significatifs avant de les entrer.
Vous pouvez créer ces patchs sur plusieurs lignes
a_patch = mock.patch('aaaaaaa')
b_patch = mock.patch('bbbbbbb')
c_patch = mock.patch('ccccccc')
with a_patch as a, b_patch as b, as c:
do_something()