Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Suponga que tiene tres objetos que se adquieren a través de gestor de contexto, por ejemplo, bloqueo A, una conexión db y un socket IP. Puede adquirirlos por:

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

Sin embargo, hay una manera de hacerlo en un bloque? algo así como

with lock,db_con,socket:
   #do stuff

Además, es posible, dada una matriz de longitud desconocida de objetos que tienen gestores de contexto, es posible de alguna manera hacer:

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

Si la respuesta es "no", es que debido a que la necesidad de esta característica implica un mal diseño, o tal vez debería sugerir que en un pep? :-P

¿Fue útil?

Solución

Python 2.7 y 3.1 y superior , se puede escribir:

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

Este es normalmente el mejor método para su uso, pero si usted tiene una lista desconocida de longitud de gestores de contexto que va a necesitar uno de los siguientes métodos.


Python 3.3 , se puede introducir una lista desconocida de longitud de gestores de contexto mediante el uso de contextlib.ExitStack :

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

Esto le permite crear los gestores de contexto a medida que los va a agregar a la ExitStack, lo que evita el posible problema con contextlib.nested (mencionado más adelante).

contextlib2 proporciona una backport de ExitStack para Python 2.6 y 2.7.


Python 2.6 y por debajo de noreferrer, puede utilizar contextlib.nested :

from contextlib import nested

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

es equivalente a:

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

Tenga en cuenta que esto no es exactamente el mismo que normalmente utilizando with anidada, porque A(), B() y C() todos serán llamados inicialmente, antes de entrar en los gestores de contexto. Esto no funcionará correctamente si una de estas funciones lanza una excepción.

contextlib.nested está en desuso en las nuevas versiones de Python a favor de los métodos anteriores.

Otros consejos

La primera parte de su pregunta es posible en Python 3.1 .

  

Con más de un artículo, los gestores de contexto se procesan como si instrucciones múltiples se anida:

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

es equivalente a

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

cambiado en la versión 3.1 : Soporte para múltiples expresiones de contexto

@ de interjay respuesta es correcta. Sin embargo, si lo que necesita hacer esto para gestores de contexto largos, por ejemplo gestores de contexto mock.patch, a continuación, se da cuenta rápidamente que desea romper este a través de líneas. Resulta que no se puede envolver en parens, así que hay que emplear estas últimas. Aquí es lo que parece:

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

La segunda parte de su pregunta se resuelve con contextlib.ExitStack en Python 3.3 .

A raíz de la respuesta de @ sage88 siempre se puede asignar esos parches tener nombres de variables significativas antes de entrar en ellos.

Se puede crear esos parches en múltiples líneas

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()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top