파이썬“with”문장은 무엇을 위해 고안 되었습니까?


418

나는 with오늘 처음으로 파이썬 진술을 보았습니다. 나는 몇 달 동안 파이썬을 가볍게 사용했지만 그 존재를 알지 못했습니다! 다소 모호한 지위를 감안할 때 물어볼 가치가 있다고 생각했습니다.

  1. with사용하기 위해 설계된 파이썬 문장 은 무엇입니까 ?
  2. 무엇을 위해 사용합니까?
  3. 내가 알아야 할 문제점이나 그 사용과 관련된 일반적인 반 패턴이 있습니까? 사용하는 것이 더 나은 경우 try..finallywith무엇입니까?
  4. 왜 더 널리 사용되지 않습니까?
  5. 어떤 표준 라이브러리 클래스와 호환됩니까?

5
기록을 위해 여기with 에 Python 3 설명서가 있습니다.
Alexey

Java 배경에서 온다면, 그것이 완전히 정확하지 않더라도 Java에서 해당 " 자원을 사용한 시도"로 기억하는 데 도움이됩니다 .
vefthym

답변:


399
  1. : 나는 단지 완전성을 위해 추가 있도록이 이미 내 앞에 다른 사용자가 응답 한 것으로 판단 with문 단순화 예외 처리를 소위 공통 준비 및 정리 작업을 캡슐화하여 상황에 맞는 관리자 . 자세한 내용은 PEP 343 에서 찾을 수 있습니다 . 예를 들어, open명령문은 자체적으로 컨텍스트 관리자이므로 파일을 열고 with사용한 명령문 의 컨텍스트에서 실행되는 동안 파일을 열어 두고 컨텍스트를 떠나 자마자 닫습니다. 예외로 인해 또는 정기적 인 제어 흐름 중에 방치했는지 여부에 관계없이. with문을 따라서와 유사한 방법으로 사용할 수 있습니다 RAII 패턴 ++ C에서 : 일부 자원에 의해 획득with당신이 with문맥 을 떠날 때

  2. 일부 예는 다음을 사용하여 파일 열기 with open(filename) as fp:하여 잠금을 획득 with lock:(여기서 lock인스턴스이다 threading.Lock). 의 contextmanager데코레이터를 사용하여 자체 컨텍스트 관리자를 구성 할 수도 있습니다 contextlib. 예를 들어, 현재 디렉토리를 일시적으로 변경 한 다음 원래 위치로 돌아 가야 할 때 자주 사용합니다.

    from contextlib import contextmanager
    import os
    
    @contextmanager
    def working_directory(path):
        current_dir = os.getcwd()
        os.chdir(path)
        try:
            yield
        finally:
            os.chdir(current_dir)
    
    with working_directory("data/stuff"):
        # do something within data/stuff
    # here I am back again in the original working directory

    여기에 일시적으로 리디렉션 또 다른 예입니다 sys.stdin, sys.stdoutsys.stderr다른 파일 핸들 나중에 복원을하기 :

    from contextlib import contextmanager
    import sys
    
    @contextmanager
    def redirected(**kwds):
        stream_names = ["stdin", "stdout", "stderr"]
        old_streams = {}
        try:
            for sname in stream_names:
                stream = kwds.get(sname, None)
                if stream is not None and stream != getattr(sys, sname):
                    old_streams[sname] = getattr(sys, sname)
                    setattr(sys, sname, stream)
            yield
        finally:
            for sname, stream in old_streams.iteritems():
                setattr(sys, sname, stream)
    
    with redirected(stdout=open("/tmp/log.txt", "w")):
         # these print statements will go to /tmp/log.txt
         print "Test entry 1"
         print "Test entry 2"
    # back to the normal stdout
    print "Back to normal stdout again"

    마지막으로, 임시 폴더를 만들어 컨텍스트를 떠날 때 정리하는 또 다른 예는 다음과 같습니다.

    from tempfile import mkdtemp
    from shutil import rmtree
    
    @contextmanager
    def temporary_dir(*args, **kwds):
        name = mkdtemp(*args, **kwds)
        try:
            yield name
        finally:
            shutil.rmtree(name)
    
    with temporary_dir() as dirname:
        # do whatever you want

20
RAII에 비교를 추가해 주셔서 감사합니다. 내가 알아야 할 모든 것을 알려주는 C ++ 프로그래머로서.
Fred Thomsen

알겠습니다. 이것을 명확히하겠습니다. 당신은 with명령문이 명령이 완료 될 때까지 데이터로 변수를 채우고 변수를 해제하도록 설계 되었다고 말하고 있습니까?
Musixauce3000

py 스크립트를 여는 데 사용했기 때문입니다. with open('myScript.py', 'r') as f: pass. f문서를 f일반 open문 을 통해 할당했을 때 나타나는 내용이므로 문서의 텍스트 내용을보기 위해 변수를 호출 할 수있을 것으로 예상했습니다 f = open('myScript.py').read(). 그러나 대신 나는 다음을 얻었다 <_io.TextIOWrapper name='myScript.py' mode='r' encoding='cp1252'>. 무슨 뜻이에요?
Musixauce3000

3
@ Musixauce3000- withread사용해도 실제 파일 이 필요하지 않습니다 . with호출 open- 당신이 그것으로 무엇을해야하는지 알 수 없습니다 - 당신은 예를 추구 수행 할 수 있습니다.
Tony Suffolk 66

@ Musixauce3000 with명령문은 변수가 데이터로 채워지거나 명령이 완료 될 때까지 환경을 약간 변경 한 다음 필요한 정리 작업을 수행 할 수 있습니다. 정리할 수있는 정리는 열린 파일을 닫거나이 예제에서 @Tamas가 가지고있는 것처럼 디렉토리를 이전 위치로 다시 변경하는 등의 작업입니다. 파이썬에는 가비지 콜렉션이 있으므로 변수를 해제하는 것은 중요하지 않습니다. 유스 케이스. with일반적으로 다른 종류의 정리에 사용됩니다.
Bob Steinke

89

두 가지 흥미로운 강의를 제안합니다.

1.with 문은 콘텍스트 관리자에 의해 정의 된 방식으로 블록의 실행을 포장하는 데 사용된다. 이를 통해 일반적인 try...except...finally재사용 패턴을 캡슐화하여 편리하게 재사용 할 수 있습니다.

2. 다음과 같은 작업을 수행 할 수 있습니다.

with open("foo.txt") as foo_file:
    data = foo_file.read()

또는

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

또는 (Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
   for line in input_file:
     output_file.write(parse(line))

또는

lock = threading.Lock()
with lock:
    # Critical section of code

3. 반 패턴이 보이지 않습니다. 파이썬으로
인용 인용 :

try..finally는 좋다. 와 함께하는 것이 좋습니다.

4.try..catch..finally 다른 언어의 문장 을 사용하는 프로그래머의 습관과 관련이 있다고 생각합니다 .


4
스레딩 동기화 객체를 다룰 때 실제로 자체적으로 발생합니다. 파이썬에서는 비교적 드물지만, 필요할 때 실제로 필요합니다 with.
detly

1
diveintopython.org가 다운되었습니다 (영구적으로?). 에서 미러 diveintopython.net
snuggles

좋은 대답의 예, 열린 파일은 파일 작업이 사용자 정의 참조 이름으로 깨끗하게 숨겨져 있음을 보여주는 열기, io, 무대 뒤에서 보여주는 주요 예입니다.
Angry 84

40

Python with문은 Resource Acquisition Is InitializationC ++에서 일반적으로 사용되는 관용구 의 내장 언어 지원입니다 . 운영 체제 자원을 안전하게 확보하고 해제 할 수 있도록 고안되었습니다.

with문은 범위 / 블록 내에서 자원을 만듭니다. 블록 내의 리소스를 사용하여 코드를 작성합니다. 블록이 종료되면 블록의 코드 결과에 관계없이 (즉, 블록이 정상적으로 종료되는지 또는 예외로 인해) 리소스가 완전히 해제됩니다.

with명령문에 필요한 프로토콜을 준수하는 Python 라이브러리의 많은 리소스가 기본적으로 사용할 수 있습니다. 그러나 누구나 잘 문서화 된 프로토콜을 구현하여 with 문에서 사용할 수있는 리소스를 만들 수 있습니다. PEP 0343

파일, 네트워크 연결, 잠금 등과 같이 명시 적으로 포기해야하는 리소스를 응용 프로그램에서 얻을 때마다 사용하십시오.


27

완성도를 높이기 위해 가장 유용한 유스 케이스를 추가하겠습니다 with.

나는 많은 과학 계산을 수행하고 일부 활동 Decimal에는 임의의 정밀 계산을 위해 라이브러리 가 필요합니다 . 내 코드의 일부에는 고정밀이 필요하고 대부분의 다른 파트에는 정밀도가 떨어집니다.

기본 정밀도를 낮은 숫자로 설정 한 다음 with일부 섹션에 대해보다 정확한 답변을 얻는 데 사용 합니다.

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

나는 이것을 하이퍼 지오메트리 테스트와 함께 많이 사용합니다. 게놈 스케일 계산을 수행 할 때 반올림 및 오버플로 오류에주의해야합니다.


26

반 패턴의 예 withwith외부 루프 를 갖는 것이 더 효율적일 때 내부 루프 를 사용하는 것일 수 있습니다.

예를 들어

for row in lines:
    with open("outfile","a") as f:
        f.write(row)

vs

with open("outfile","a") as f:
    for row in lines:
        f.write(row)

첫 번째 방법은 파일을 열고 닫는 것입니다 row. 두 번째 방법과 비교할 때 파일을 한 번만 열고 닫는 것과 비교하여 성능 문제가 발생할 수 있습니다.


10

PEP 343- 'with'문을 참조하십시오 . 끝에 섹션이 있습니다.

... try / finally 문의 표준 사용을 고려할 수 있도록하기 위해 Python 언어에 "with"라는 새 명령문이 있습니다.


5

포인트 1, 2 및 3은 합리적으로 잘 설명되어 있습니다.

4 : 그것은 비교적 새롭고 python2.6 +에서만 사용 가능합니다 (또는 python2.5 사용 from __future__ import with_statement)



3

즉시 사용 가능한 지원의 또 다른 예와 내장 open()동작 방식에 익숙 할 때 처음에는 약간 당혹 스러울 수있는 connection예는 다음과 같은 널리 사용되는 데이터베이스 모듈의 객체입니다.

connection오브젝트 콘텍스트 매니저이며 등은 즉시 사용 사용될 수있는 with-statement, 그러나, 상기 참고 사용시 :

with-block예외가 있거나없이 완료 되면 연결이 닫히지 않습니다 . with-block예외가 있는 완료의 경우 트랜잭션이 롤백되고, 그렇지 않으면 트랜잭션이 커밋됩니다.

이는 프로그래머가 연결 자체를 닫는 데주의를 기울여야하지만 psycopg2 문서에with-statements 표시된대로 연결을 확보하여 여러 번 사용할 수 있음을 의미합니다 .

conn = psycopg2.connect(DSN)

with conn:
    with conn.cursor() as curs:
        curs.execute(SQL1)

with conn:
    with conn.cursor() as curs:
        curs.execute(SQL2)

conn.close()

위의 예에서 cursor객체의 개체 psycopg2는 컨텍스트 관리자라는 것을 알 수 있습니다. 동작에 대한 관련 문서에서 :

cursor엑시트 가 종료 되면 with-block닫히고 결국 연관된 자원을 해제합니다. 트랜잭션 상태는 영향을받지 않습니다.


3

파이썬에서 일반적으로 " with "문은 파일을 열고 파일에있는 데이터를 처리하고 close () 메서드를 호출하지 않고 파일을 닫는 데 사용됩니다. "with"문은 정리 활동을 제공하여 예외 처리를 단순화합니다.

와의 일반적인 형태 :

with open(“file name”, mode”) as file-var:
    processing statements

참고 : file-var.close ()에 close ()를 호출하여 파일을 닫을 필요가 없습니다 .

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