[python] ‘with’문에 여러 변수가 있습니까?

with파이썬 에서 명령문을 사용하여 둘 이상의 변수를 선언 할 수 있습니까?

다음과 같은 것 :

from __future__ import with_statement

with open("out.txt","wt"), open("in.txt") as file_out, file_in:
    for line in file_in:
        file_out.write(line)

… 또는 동시에 두 개의 리소스를 정리하는 것이 문제입니까?



답변

v3.1Python 2.7 이후의 Python 3 에서 가능합니다 . 새로운 with구문 은 여러 컨텍스트 관리자를 지원합니다.

with A() as a, B() as b, C() as c:
    doSomething(a,b,c)

는 달리 contextlib.nested,이 보장 a하고 b있는 것은 __exit__()‘경우에도라고 s의 C()또는 그것의 __enter__()메소드가 예외를 발생시킵니다.

나중에 정의 할 때 이전 변수를 사용할 수도 있습니다 ( 아래의 h / t Ahmad ).

with A() as a, B(a) as b, C(a, b) as c:
    doSomething(a, c)


답변

contextlib.nested 이것을 지원합니다 :

import contextlib

with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):

   ...

업데이트 :
관련 문서를 인용하려면 contextlib.nested:

버전 2.7부터 더 이상 사용되지 않음 : with-statement는 이제 혼란스러운 오류가 발생하지 않는이 기능을 직접 지원합니다.

자세한 내용은 Rafał Dowgird의 답변 을 참조하십시오.


답변

변수를 줄로 나누면 백 슬래시를 사용하여 줄 바꿈을 래핑해야합니다.

with A() as a, \
     B() as b, \
     C() as c:
    doSomething(a,b,c)

파이썬이 대신 튜플을 생성하기 때문에 괄호가 작동하지 않습니다.

with (A(),
      B(),
      C()):
    doSomething(a,b,c)

튜플에는 __enter__속성이 없으므로 오류가 발생합니다 (설명 적이 지 않고 클래스 유형을 식별하지 못함).

AttributeError: __enter__

as괄호 안에 사용하려고하면 파이썬은 구문 분석시 실수를 포착합니다.

with (A() as a,
      B() as b,
      C() as c):
    doSomething(a,b,c)

SyntaxError : 유효하지 않은 구문

https://bugs.python.org/issue12782 는이 문제와 관련이있는 것 같습니다.


답변

나는 당신이 대신 이것을하고 싶다고 생각합니다.

from __future__ import with_statement

with open("out.txt","wt") as file_out:
    with open("in.txt") as file_in:
        for line in file_in:
            file_out.write(line)


답변

Python 3.3부터는 모듈 에서 클래스 ExitStack를 사용할 수 있습니다 contextlib.

동적 으로 인식되는 컨텍스트 인식 개체를 관리 할 수 ​​있으므로 처리 할 파일 수를 모르는 경우 특히 유용합니다.

설명서에 언급 된 표준 사용 사례는 동적 파일 수를 관리하는 것입니다.

with ExitStack() as stack:
    files = [stack.enter_context(open(fname)) for fname in filenames]
    # All opened files will automatically be closed at the end of
    # the with statement, even if attempts to open files later
    # in the list raise an exception

일반적인 예는 다음과 같습니다.

from contextlib import ExitStack

class X:
    num = 1

    def __init__(self):
        self.num = X.num
        X.num += 1

    def __repr__(self):
        cls = type(self)
        return '{cls.__name__}{self.num}'.format(cls=cls, self=self)

    def __enter__(self):
        print('enter {!r}'.format(self))
        return self.num

    def __exit__(self, exc_type, exc_value, traceback):
        print('exit {!r}'.format(self))
        return True

xs = [X() for _ in range(3)]

with ExitStack() as stack:
    print(stack._exit_callbacks)
    nums = [stack.enter_context(x) for x in xs]
    print(stack._exit_callbacks)
print(stack._exit_callbacks)
print(nums)

산출:

deque([])
enter X1
enter X2
enter X3
deque([<function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86158>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f861e0>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86268>])
exit X3
exit X2
exit X1
deque([])
[1, 2, 3]


답변

Python 3.1 이상에서는 여러 컨텍스트 표현식을 지정할 수 있으며 여러 with명령문이 중첩 된 것처럼 처리됩니다 .

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

에 해당

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

이는 또한 두 번째 표현식의 첫 번째 표현식에서 별명을 사용할 수 있음을 의미합니다 (db 연결 / 커서 작업시 유용함).

with get_conn() as conn, conn.cursor() as cursor:
    cursor.execute(sql)


답변