'with'문에 여러 변수가 있습니까?


391

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)

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


[expr1, expr2]를 f :로 사용하고 f [0]과 f [1]을 사용하십시오.
jbasko

하고 좋은이 때문에 수입 뭔가 할 필요가 없습니다 ....을하지만,하지 작업 AttributeError를 수행합니다 '목록'개체가 어떤 속성 '이 없습니다 출구 '
복어

파이썬이 클로저를 막았다면 with 문이 필요 없을 것입니다
BT

with 문을 사용할 필요 가 없습니다 . 그렇습니까? file_out 및 file_in을 None으로 설정 한 다음 try / except / finally를 열어서 시도하고 처리 한 다음 None이 아닌 경우 마지막에 닫을 수 있습니다. 이중 들여 쓰기가 필요하지 않습니다.
M Katz

1
이 답변들 중 다수는 두 가지 이상의 진술에 대한 필요성을 다루지 않습니다. 이론적으로 수십 개의 컨텍스트를 열어야하는 응용 프로그램이있을 수 있으며, 중첩 길이가 매우 빠르면 중첩이 매우 빠르게 떨어집니다.
ThorSummoner

답변:


666

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)

1
에서와 같이 with 문과 동일한 필드를 설정할 수 with open('./file') as arg.x = file:있습니까?
Charlie Parker

13
또한 가능합니다 : A ()를 a로, B (a)를 b로, C (a, b)를 c로 사용 :
Ahmad Yoosofan

클래스 test2 : x = 1; t2.x.readlines ()에서 l1의 경우 : open ( 'f2.txt')를 t2.x로하여 t2 = test2 () : print (l1); # Charlie Parker # python 3.6에서 테스트
Ahmad Yoosofan

1
, 참고하시기 바랍니다 as선택 사항입니다.
Sławomir Lenart

말하는 SławomirLenart @ 무엇인지 명확히 : as당신이 객체가 필요한 경우 필요 a하거나 b,하지만 전체를 as a하거나 as b필요하지 않습니다
치프 리안 Tomoiagă

56

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의 답변 을 참조하십시오.


34
유감스럽게도 nested콘텍스트 관리자는 실수이므로 절대 사용해서는 안된다고 생각합니다 . 이 예제에서 두 번째 파일을 열면 예외가 발생하면 첫 번째 파일이 전혀 닫히지 않으므로 컨텍스트 관리자 사용 목적을 완전히 파괴합니다.
Rafał Dowgird

왜 그런 말을 해? 설명서에 따르면 중첩 사용은 중첩 된 'with'와 동일합니다.
James Hopkin

@Rafal : 매뉴얼을 보면 파이썬이 with 문을 올바르게 중첩한다는 것을 알 수 있습니다. 실제 문제는 두 번째 파일을 닫을 때 예외가 발생하는 것입니다.
알 수 없음

10
@James : 아니요. docs.python.org/library/contextlib.html#contextlib.nested 에있는 문서의 해당 코드 는 표준 중첩 with블록 과 다릅니다 . 관리자는 with 블록을 입력 하기 전에 순서대로 생성됩니다 . m1, m2, m3 = A (), B (), C () B () 또는 C ()가 예외로 실패하는 경우 A ( )는 가비지 수집기입니다.
Rafał Dowgird

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

36

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

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 는이 문제와 관련이있는 것 같습니다.


16

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

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)

5
그것이 내가 현재하는 방법이지만, 둥지는 내가 원하는 것보다 두 배나 깊습니다.
복어

나는 이것이 가장 깨끗한 접근법이라고 생각합니다-다른 접근법은 읽기가 더 어려울 것입니다. Alex Martelli의 답변은 당신이 원하는 것에 더 가깝지만 읽기 쉽지 않습니다. 중첩이 왜 그런 문제입니까?
Andrew Hare

7
큰 의미는 없지만 "이것을 가져 오기"(일명 "Zen of Python")에 따르면 "평면이 중첩보다 낫다"는 것이 표준 라이브러리에 contextlib.nested를 추가 한 이유입니다. BTW, 3.1은보다 직접적인 지원을 위해 "A ()를 a (a), B ()를 b : (b)"로하는 새로운 구문을 가질 수 있습니다 (패치가 있지만 지금까지 BDFL 선언은 없습니다). 완벽한 것으로 간주되지는 않지만 원치 않는 중첩을 피하는 것이 핵심 Python 개발자들 사이에서 널리 공유되는 목표입니다).
Alex Martelli

2
@Alex : 매우 사실이지만 "가독성"도 고려해야합니다.
Andrew Hare

4
@Andrew : 한 수준의 들여 쓰기가 프로그램의 의도 된 논리를 더 잘 표현한다고 생각합니다. 즉, "원자 적으로"두 개의 변수를 작성하고 나중에 함께 정리하는 것입니다. 예외 문제는 거래 차단기라고 생각하십시오
복어

12

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]

0

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.