source

여러 콘텍스트 매니저에 "with" 블록을 생성하시겠습니까?

bestscript 2023. 1. 6. 19:52

여러 콘텍스트 매니저에 "with" 블록을 생성하시겠습니까?

컨텍스트 매니저를 통해 취득한 오브젝트(A lock, db connection, ip socket 등)가 3개 있다고 가정합니다.다음 방법으로 입수할 수 있습니다.

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

하지만 한 블록 안에 할 수 있는 방법은 없을까?비슷한 것

with lock,db_con,socket:
   #do stuff

또한 컨텍스트 매니저가 있는 알 수 없는 길이의 객체가 배열되어 있는 경우 다음과 같은 작업을 수행할 수 있습니까?

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

"아니오"라고 대답한 경우, 이러한 기능의 필요성은 디자인이 나쁘기 때문일까요, 아니면 격려로 제안해야 할까요? :-P

Python 2.73.1 이상에서는 다음과 같이 쓸 수 있습니다.

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

일반적으로 이 방법을 사용하는 것이 가장 좋지만, 알 수 없는 길이의 컨텍스트 관리자 목록이 있는 경우 다음 방법 중 하나가 필요합니다.


Python 3.3에서는 다음을 사용하여 알 수 없는 길이의 컨텍스트 매니저 목록을 입력할 수 있습니다.

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

이것에 의해, 콘텍스트 매니저를 추가하면서, 그것들을 작성할 수 있습니다.ExitStack이를 통해 에 발생할 수 있는 문제를 방지할 수 있습니다.contextlib.nested(아래 참조).

contextlib2는 Python 2.6 및 2.7의 백포트를 제공합니다.


Python 2.6 이하에서는 다음을 사용할 수 있습니다.

from contextlib import nested

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

는 다음과 같습니다.

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

이것은 보통 nested를 사용하는 것과 완전히 동일하지 않습니다.with,왜냐면A(),B(),그리고.C()콘텍스트 매니저로 이행하기 전에, 처음에 모든 것이 콜 됩니다.이러한 함수 중 하나가 예외를 발생시키면 올바르게 작동하지 않습니다.

contextlib.nested는 위의 메서드보다 새로운 Python 버전에서는 권장되지 않습니다.

python 3.10부터 괄호 안의 콘텍스트 매니저를 사용할 수 있게 되었습니다!감사합니다 @iforapsy!

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

python 버전 3.10 미만의 경우

@interjay's Answer는 정답입니다.그러나 mock.patch 콘텍스트 매니저 등 긴 콘텍스트 매니저에 대해 이 작업을 수행해야 하는 경우에는 이 작업을 여러 회선에 걸쳐 중단해야 한다는 것을 금방 알 수 있습니다.파렌으로 포장할 수 없기 때문에 백슬래시를 사용해야 합니다.다음은 예를 제시하겠습니다.

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

질문의 첫 부분은 Python 3.1에서 가능합니다.

항목이 여러 개일 경우 컨텍스트 매니저는 문이 여러 개 중첩된 것처럼 처리됩니다.

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

와 동등하다

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

버전 3.1에서 변경: 멀티 컨텍스트 표현 지원

, 그럼 두 은 '어울리지 않다'로 .contextlib.ExitStackPython 3.3에 있습니다.

@sage88의 응답에 따라 패치를 입력하기 전에 항상 의미 있는 변수 이름을 지정하도록 패치를 할당할 수 있습니다.

이러한 패치를 여러 줄에 걸쳐 생성할 수 있습니다.

a_patch = mock.patch('aaaaaaa') 
b_patch = mock.patch('bbbbbbb')
c_patch = mock.patch('ccccccc') 
with a_patch as a, b_patch as b, c_patch as c:    
    do_something()

언급URL : https://stackoverflow.com/questions/3024925/create-a-with-block-on-several-context-managers