Python Language
컨텍스트 관리자 ( "with"문)
수색…
소개
파이썬의 컨텍스트 관리자가 널리 사용되는 동안, 사용법의 목적을 이해하는 사람은 거의 없습니다. 파일 읽기 및 쓰기와 같이 일반적으로 사용되는이 명령문은 응용 프로그램이 시스템 메모리를 절약하고 특정 프로세스에만 특정 리소스가 사용되도록하여 리소스 관리를 향상시키는 데 도움을줍니다. 이 주제는 파이썬의 컨텍스트 매니저의 사용을 설명하고 설명합니다.
통사론
- "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')