수색…


소개

파이썬의 컨텍스트 관리자가 널리 사용되는 동안, 사용법의 목적을 이해하는 사람은 거의 없습니다. 파일 읽기 및 쓰기와 같이 일반적으로 사용되는이 명령문은 응용 프로그램이 시스템 메모리를 절약하고 특정 프로세스에만 특정 리소스가 사용되도록하여 리소스 관리를 향상시키는 데 도움을줍니다. 이 주제는 파이썬의 컨텍스트 매니저의 사용을 설명하고 설명합니다.

통사론

  • "context_manager"( "별칭") ( "context_manager"( "별칭")?) * :

비고

컨텍스트 관리자는 PEP 343 에서 정의됩니다. 이것들은 try ... finally 구조보다 자원 관리를위한보다 간결한 메커니즘으로 사용하기위한 것입니다. 공식적인 정의는 다음과 같습니다.

이 PEP에서 컨텍스트 관리자는 with 문의 본문으로 들어가거나 빠져 나올 때 호출되는 __enter__()__exit__() 메소드를 제공합니다.

그런 다음 with 문을 다음과 같이 정의합니다.

with EXPR as VAR:
    BLOCK

위 성명서의 번역은 다음과 같습니다.

   mgr = (EXPR)
   exit = type(mgr).__exit__  # Not calling it yet
   value = type(mgr).__enter__(mgr)
   exc = True
   try:
       try:
           VAR = value  # Only if "as VAR" is present
           BLOCK
       except:
           # The exceptional case is handled here
           exc = False
           if not exit(mgr, *sys.exc_info()):
               raise
           # The exception is swallowed if exit() returns true
   finally:
       # The normal and non-local-goto cases are handled here
       if exc:
           exit(mgr, None, None, None)

컨텍스트 관리자 소개 및 with 문

컨텍스트 관리자는 컨텍스트 (코드 블록) 가 시작 되고 끝날 때 통보되는 객체입니다. 일반적으로 with 문과 with 합니다. 알림을 처리합니다.

예를 들어 파일 객체는 컨텍스트 관리자입니다. 컨텍스트가 끝나면 파일 객체는 자동으로 닫힙니다.

open_file = open(filename)
with open_file:
    file_contents = open_file.read()

# the open_file object has automatically been closed.

위의 예제는 일반적으로 as 키워드를 사용하여 단순화됩니다.

with open(filename) as open_file:
    file_contents = open_file.read()

# the open_file object has automatically been closed.

블록 실행을 끝내면 컨텍스트 관리자의 exit 메소드가 호출됩니다. 여기에는 예외가 포함되어있어 오류로 인해 열려있는 파일 또는 연결이 중간에 종료 될 때 유용 할 수 있습니다. 파일 / 연결을 제대로 닫지 않고 스크립트를 종료하면 데이터 손실이나 기타 문제가 발생할 수 있다는 잘못된 생각입니다. 컨텍스트 관리자를 사용하면 이러한 방식으로 손상이나 손실을 방지하기 위해 항상 예방 조치를 취할 수 있습니다. 이 기능은 Python 2.5에서 추가되었습니다.

대상 지정

많은 컨텍스트 관리자가 입력 될 때 객체를 반환합니다. 그 개체를 with 문의 새로운 이름에 할당 할 수 있습니다.

예를 들어 with 문에서 데이터베이스 연결을 사용하면 커서 객체를 얻을 수 있습니다.

with database_connection as cursor:
    cursor.execute(sql_query)

파일 객체는 스스로를 반환합니다. 이렇게하면 파일 객체를 열고 하나의 표현식에서 컨텍스트 관리자로 사용할 수 있습니다.

with open(filename) as open_file:
    file_contents = open_file.read()

자신 만의 콘텍스트 관리자 작성하기

컨텍스트 관리자는 __enter__()__exit__() 과 같은 두 가지 마법 메서드를 구현하는 객체입니다 __exit__() 다른 메서드도 구현할 수 있음).

class AContextManager():

    def __enter__(self):
        print("Entered")
        # optionally return an object
        return "A-instance"

    def __exit__(self, exc_type, exc_value, traceback):
        print("Exited" + (" (with an exception)" if exc_type else ""))
        # return True if you want to suppress the exception

예외가있는 컨텍스트가 종료되면 해당 예외에 대한 정보가 triple exc_type , exc_value , traceback (이들은 sys.exc_info() 함수에서 반환 된 변수와 동일 함)로 전달됩니다. 컨텍스트가 정상적으로 종료되면이 세 인수는 모두 None 됩니다.

예외가 발생하고 __exit__ 메소드로 전달되면, 메소드는 예외를 억제하기 위해 True 를 리턴 할 수 있습니다. __exit__ 함수의 끝에서 예외가 다시 발생합니다.

with AContextManager() as a:
    print("a is %r" % a)
# Entered
# a is 'A-instance'
# Exited

with AContextManager() as a:
    print("a is %d" % a)
# Entered
# Exited (with an exception)
# Traceback (most recent call last):
#   File "<stdin>", line 2, in <module>
# TypeError: %d format: a number is required, not str

두 번째 예제에서 with - 문 본문의 중간에서 예외가 발생하더라도 예외가 외부 범위로 전달되기 전에 __exit__ 처리기가 계속 실행됩니다.

__exit__ 메소드 만 있으면 컨텍스트 매니저의 인스턴스를 반환 할 수 있습니다 :

class MyContextManager:
    def __enter__(self):
        return self

    def __exit__(self):
        print('something')

생성자 구문을 사용하여 자신의 contextmanager 작성하기

contextlib.contextmanager 데코레이터를 사용하면 생성기 구문을 사용하여 컨텍스트 관리자를 작성할 수도 있습니다.

import contextlib

@contextlib.contextmanager
def context_manager(num):
    print('Enter')
    yield num + 1
    print('Exit')

with context_manager(2) as cm:
    # the following instructions are run when the 'yield' point of the context
    # manager is reached.
    # 'cm' will have the value that was yielded
    print('Right in the middle with cm = {}'.format(cm))

생산 :

Enter
Right in the middle with cm = 3
Exit

데코레이터는 생성기를 하나로 변환하여 컨텍스트 관리자를 작성하는 작업을 단순화합니다. yield 식 앞에 모든 것이 __enter__ 메서드가되면 yield 된 값은 생성자에서 반환 한 값이되고 (with 문에서 변수에 바인딩 될 수 있음) yield 식 뒤에있는 모든 것이 __exit__ 메서드가됩니다.

예외가 콘텍스트 관리자에 의해 처리되어야한다면, try..except..finally - 블록은 상기 발전기에서 발생하고 예외로 기록 될 수 with - 블록이 예외 블록에 의해 처리 될 것이다.

@contextlib.contextmanager
def error_handling_context_manager(num):
    print("Enter")
    try:
        yield num + 1
    except ZeroDivisionError:
        print("Caught error")
    finally:
        print("Cleaning up")
    print("Exit")

with error_handling_context_manager(-1) as cm:
    print("Dividing by cm = {}".format(cm))
    print(2 / cm)

이것은 다음을 생성합니다.

Enter
Dividing by cm = 0
Caught error
Cleaning up
Exit

다중 컨텍스트 관리자

동시에 여러 개의 컨텐츠 관리자를 열 수 있습니다.

with open(input_path) as input_file, open(output_path, 'w') as output_file:

    # do something with both files. 
    
    # e.g. copy the contents of input_file into output_file
    for line in input_file:
        output_file.write(line + '\n')

컨텍스트 관리자를 중첩하는 것과 같은 효과가 있습니다.

with open(input_path) as input_file:
    with open(output_path, 'w') as output_file:
        for line in input_file:
            output_file.write(line + '\n')

리소스 관리

class File():
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):
        self.open_file = open(self.filename, self.mode)
        return self.open_file

    def __exit__(self, *args):
        self.open_file.close()

__init__() 메서드는 객체를 설정합니다.이 경우 파일 이름과 모드를 열고 파일을 설정합니다. __enter__() 가 열리고 파일을 반환하고 __exit__() 가 파일을 닫습니다.

이 마법의 방법을 사용하여 ( __enter__ , __exit__ ) 쉽게 사용할 수있는 개체를 구현할 수 with with 문을.

File 클래스 사용 :

for _ in range(10000):
    with File('foo.txt', 'w') as f:
        f.write('foo')


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow