Frage

    

Diese Frage bereits eine Antwort hier:

    
            
  •              Mehrere Variablen in a 'mit' Aussage?                                      6 Antworten                          
  •     
    

Angenommen, Sie drei Objekte haben Sie über das Kontextmanager erwerben, zum Beispiel ein Schloss, eine DB-Verbindung und eine IP-Buchse. Sie können sie erwerben durch:

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

Aber ist es eine Möglichkeit, es in einem Block zu tun? so etwas wie

with lock,db_con,socket:
   #do stuff

Darüber hinaus ist es möglich, da eine Reihe von unbekannter Länge von Objekten, die Kontext-Manager haben, ist es möglich, irgendwie zu tun:

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

Wenn die Antwort „nein“ ist, ist es, weil die Notwendigkeit für ein solches Feature schlechtes Design impliziert, oder vielleicht sollte ich es in einem pep vorschlagen? :-P

War es hilfreich?

Lösung

In Python 2.7 und 3.1 und höher , können Sie schreiben:

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

Dies ist normalerweise die beste Methode zu verwenden, aber wenn Sie eine unbekannte Länge Liste der Kontext-Manager haben werden Sie eine der folgenden Methoden benötigen.


In Python 3.3 können Sie eine unbekannte Länge Liste der Kontext-Manager eingeben, indem Sie mit contextlib.ExitStack :

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

So können Sie die Kontext-Manager erstellen, wie Sie sie an die ExitStack hinzufügen, die das mögliche Problem mit contextlib.nested verhindert (unten erwähnt).

contextlib2 bietet eine Rückportierung von ExitStack für Python 2.6 und 2.7.


In Python 2.6 und unter können Sie a href verwenden <= "https://docs.python.org/2/library/contextlib.html#contextlib.nested" rel = "noreferrer „> contextlib.nested :

from contextlib import nested

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

entspricht:

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

Beachten Sie, dass dies nicht genau das gleiche, wie sie normalerweise verschachtelten with verwenden, weil A(), B() und C() werden all zunächst aufgerufen werden, bevor die Kontextmanager eingeben. Dies wird nicht korrekt funktionieren, wenn eine dieser Funktionen eine Ausnahme auslöst.

contextlib.nested wird in neueren Python-Versionen zugunsten der oben genannten Methoden veraltet.

Andere Tipps

Der erste Teil Ihrer Frage ist möglich in Python 3.1 .

  

Mit mehr als einem Elemente wird der Kontext-Manager verarbeitet, als ob mehrere mit Anweisungen verschachtelt wurden:

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

entspricht

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

Changed in Version 3.1 : Unterstützung für mehrere Kontextausdrücke

@ interjay Antwort ist richtig. Wenn Sie jedoch müssen diese für lange Kontext-Manager tun, zum Beispiel mock.patch Kontext-Manager, dann merkt man schnell Sie diese über mehrere Zeilen brechen wollen. Stellt sich heraus, man kann sie nicht in Pars wickeln, so dass Sie Schrägstriche haben zu verwenden. Hier ist, wie das aussieht:

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

Der zweite Teil Ihrer Frage ist gelöst mit contextlib.ExitStack in Python 3.3 .

auf Anschluss von @ sage88 Antwort können Sie immer diese Patches zuweisen sinnvolle Variablennamen haben, bevor Sie in sie eingegeben werden.

Sie können diese Patches in mehreren Zeilen erstellen

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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top