2010-06-11 9 views
117

컨텍스트 관리자를 통해 획득 한 세 개의 개체 (예 : 잠금, db 연결 및 ip 소켓)가 있다고 가정합니다. 다음과 같은 방법으로 그들을 얻을 수 있습니다 :python : 여러 컨텍스트 관리자에서 "with"블록을 만듭니다.

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

그러나 하나 개의 블록에 그것을 할 수있는 방법은 무엇입니까? 대답은 "아니오"이다

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

경우 : 또한

with lock,db_con,socket: 
    #do stuff 

같은, 그것은 가능하며, 상황에 맞는 관리자가 개체의 알 수없는 길이의 배열을 지정해, 어떻게 든 할 수 있습니다 그러한 기능에 대한 필요성이 나쁜 디자인을 암시했기 때문에 또는 어쩌면 내가 한 덩어리로 제안해야 할 것인가? :-P

+1

[문 '과'파이썬에서 여러 변수]의 중복 가능성 (http://stackoverflow.com/questions/893333/multiple-variables-in-python-with-statement) : 여기에 그 같은 모습이다 –

답변

212

파이썬 2.6 에서와 아래, 당신은 contextlib.nested를 사용할 수 있습니다

from contextlib import nested 

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

은 동등하다 :이 정확히 일반적으로 중첩 된 with를 사용하는 것과 동일하지 않습니다

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

주, 컨텍스트 관리자에 들어가기 전에 A(), B()C()이 모두 처음에 호출되기 때문입니다. 이 함수 중 하나가 예외를 발생시킬 수 있지만 질문의 예제에서 작동하면 올바르게 작동하지 않습니다.


파이썬 2.7 및 3.1 에서 구문이 추가되었으며, contextlib.nested가 사용되지 않습니다 :

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

파이썬 3.3, 당신은 또한 알 수없는 입력 할 수 있습니다 contextlib.ExitStack을 사용하여 컨텍스트 관리자의 길이 목록 :

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

이렇게하면 ExitStack에 컨텍스트 관리자를 추가 할 때 컨텍스트 관리자를 만들 수 있으므로 contextlib.nested의 가능한 문제를 방지 할 수 있습니다.

contextlib2은 Python 2에 대해 a backport of ExitStack을 제공합니다.6 및 2.7.

+0

감사합니다! 그래서 나는 contextlib.nested (* arr)을 가진 컨텍스트 매니저의 배열에 이것을 사용할 수있다.
파이썬 2.7과 3.1의 새로운 구문에서 어떻게 든 가능합니까? – olamundo

+2

@noam : 아니요. 사실, 3.1에서'nested '에 대한 docstring은 다음과 같이 말합니다 : "with 함수의 다중 관리자 형식에 비해이 함수의 한 가지 장점은 인수 풀기를 사용하면 가변 개수의 컨텍스트 관리자 'with nested (* managers) : do_something()' " – interjay

+9

이상하게도, 한편으로는 비추천이지만, 다른 한편으로는 비추천 모듈의 대체에 대한 이점을 인정하고 있습니까? – olamundo

18

질문의 첫 번째 부분은 Python 3.1에서 가능합니다. 문 여러 중첩 한 것처럼 하나 개 이상의 항목

는, 콘텍스트 관리자는 처리 :

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

버전 3.1 변경

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

동등하다 : 지원 다중 컨텍스트 표현식의 경우

+0

감사합니다! 그러나 그것은 여전히 ​​내 모든 질문에 답하지 못했습니다. 배열에서 얼마나 많은 mangers가 존재하는지 알지 못하고 컨텍스트 관리자가 배열로 주어지는 두 번째 경우는 어떻합니까? 어떤 python3.X에서 의 결과를 [cm1, cm2, cm3, cm4, cm5]로 할 수 있습니까? .... – olamundo

+2

@noam : 질문의 두 번째 부분을 해결하려면 클래스를 작성할 수 있습니다 여러 리소스를 랩핑하고 해당 클래스에 대해'__enter__' 및'__exit__'을 구현합니다. 이미 표준 라이브러리 클래스가 있는지 확실하지 않습니다. –

+0

@Mark 나는 그것이 쉽지 않다고 생각한다. 그래서'contextlib.nested()'가 더 이상 사용되지 않는 이유이다. 다른 것들의 생성과 컨텍스트 관리자의 활성화 사이에 어떤 일이 발생하면, 정리가 원한대로 이루어지지 않을 수도 있습니다. – glglgl

7

질문의 두 번째 부분은 contextlib.ExitStack (Python 3.3)입니다.

1

@ interjay의 답변은 정확합니다. 그러나 긴 컨텍스트 관리자 (예 : mock.patch 컨텍스트 관리자)에서이 작업을 수행해야하는 경우이 작업을 여러 줄로 나누고 싶다는 것을 금방 알 수 있습니다. 괄호 안에 포장 할 수 없으므로 백 슬래시를 사용해야합니다.

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