Domanda

    

Questa domanda ha già una risposta qui:

    
            
  •              più variabili in un 'con' affermazione?                                      6 risposte                          
  •     
    

Si supponga di avere tre oggetti si acquisiscono via contesto manager, per la serratura esempio A, una connessione db e una presa ip. Si possono acquistare da:

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

Ma c'è un modo per farlo in un blocco? qualcosa come

with lock,db_con,socket:
   #do stuff

Inoltre, è possibile, dato un array di sconosciuta lunghezza di oggetti con gestori di contesto, è possibile fare in qualche modo:

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

Se la risposta è "no", è perché la necessità di tale caratteristica un implica cattiva progettazione, o forse dovrei suggerire in un pep? :-P

È stato utile?

Soluzione

Nel Python 2.7 e 3.1 e superiore , è possibile scrivere:

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

Questo è normalmente il metodo migliore per l'uso, ma se si dispone di un elenco sconosciuta di lunghezza del contesto manager avrete bisogno di uno dei metodi di seguito.


Nel Python 3.3 , è possibile inserire un elenco sconosciuta di lunghezza del contesto manager utilizzando contextlib.ExitStack :

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

Questo consente di creare i gestori di contesto come li sta aggiungendo al ExitStack, che impedisce l'eventuale problema con contextlib.nested (di cui sotto).

contextlib2 fornisce un backport di ExitStack per Python 2.6 e 2.7.


Nel Python 2.6 e al di sotto noreferrer, è possibile utilizzare contextlib.nested :

from contextlib import nested

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

è equivalente a:

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

Si noti che questo non è esattamente lo stesso come normalmente utilizzando with annidata, perché A(), B() e C() saranno tutti chiamati inizialmente, prima di entrare i gestori di contesto. Questo non funzionerà correttamente se una di queste funzioni solleva un'eccezione.

contextlib.nested è deprecato in versioni più recenti di Python a favore dei metodi di cui sopra.

Altri suggerimenti

La prima parte della tua domanda è possibile in Python 3.1 .

  

Con più di un oggetto, i gestori di contesto sono trattati come se multipla con le dichiarazioni sono stati nidificati:

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

è equivalente a

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

Modificato nella versione 3.1 : Supporto per più espressioni di contesto

@ di interjay risposta è corretta. Tuttavia, se avete bisogno di fare questo per i gestori di contesto lunghi, per il contesto manager ad esempio mock.patch, poi ti rendi conto rapidamente che si desidera rompere questo attraverso le linee. Si scopre che non si possono avvolgere in parentesi, quindi bisogna utilizzare barre rovesciate. Ecco cosa che appare come:

with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \
        mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \
        mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c:
    do_something()

La seconda parte della tua domanda è risolto con contextlib.ExitStack in Python 3.3 .

A seguito di risposta di @ sage88 si può sempre assegnare tali patch ad avere i nomi delle variabili significative prima di entrare in loro.

Si potrebbe creare quelle patch in più righe

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()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top