Python 표준 모듈--ContextManager 컨 텍스트 관리자 의 구체 적 인 용법

9345 단어 PythonContextManager
코드 를 쓸 때,우 리 는 일부 조작 을 코드 블록 에 넣 기 를 원 합 니 다.이렇게 하면 코드 블록 에서 실 행 될 때 특정한 운행 상 태 를 유지 할 수 있 고,이 코드 블록 을 떠 날 때 다른 조작 을 실행 하여 현재 상 태 를 끝 낼 수 있 습 니 다.따라서 간단하게 말하자면 상하 문 관리자 의 목적 은 대상 의 사용 범 위 를 규정 하고 범 위 를 초과 하면'처리'를 하 는 것 이다.
이 기능 은 Python 2.5 이후 에 도 입 된 것 으로 코드 를 더욱 읽 을 수 있 고 실수 하기 쉽 지 않다 는 장점 이 있 습 니 다.
1 모듈 소개
몇 년 전 파 이 썬 2.5 는 매우 특별한 키 워드 를 넣 었 는데 그것 이 바로 with 였 다.with 문 구 는 개발 자가 컨 텍스트 관리 자 를 만 들 수 있 도록 합 니 다.문맥 관리자 란 무엇 입 니까?컨 텍스트 관리 자 는 자동 으로 뭔 가 를 시작 하고 끝 낼 수 있 도록 하 는 것 입 니 다.예 를 들 어 파일 을 열 고 내용 을 쓰 고 마지막 으로 파일 을 닫 으 려 고 할 수도 있 습 니 다.이것 은 아마도 상하 문 관리자 의 가장 전형 적 인 예 일 것 이다.사실 with 문 구 를 이용 하여 파일 을 열 었 을 때 Python 은 자동 으로 컨 텍스트 관리 자 를 만 들 었 습 니 다.

with open("test/test.txt","w") as f_obj:
  f_obj.write("hello")
만약 당신 이 Python 2.4 를 사용한다 면,당신 은 오래된 방식 으로 이 임 무 를 완성 해 야 합 니 다.

f_obj = open("test/test.txt","w")
f_obj.write("hello")
f_obj.close()
컨 텍스트 관리자 뒤에서 작업 하 는 메커니즘 은 Python 을 사용 하 는 방법 입 니 다:enter__와exit__。컨 텍스트 관리자 가 어떻게 작 동 하 는 지 알 아 보기 위해 컨 텍스트 관리 자 를 만 들 려 고 합 니 다.
2 모듈 사용
2.1 컨 텍스트 관리자 클래스 만 들 기
Python 을 계속 사용 하여 파일 을 여 는 것 보다 컨 텍스트 관리 자 를 만 듭 니 다.이 컨 텍스트 관리 자 는 SQLite 데이터베이스 연결 을 만 들 것 입 니 다.작업 이 끝나 면 닫 을 것 입 니 다.다음은 간단 한 예 다.

import sqlite3

class DataConn:
  def __init__(self,db_name):
    self.db_name = db_name

  def __enter__(self):
    self.conn = sqlite3.connect(self.db_name)
    return self.conn

  def __exit__(self,exc_type,exc_val,exc_tb):
    self.conn.close()
    if exc_val:
      raise

if __name__ == "__main__":
  db = "test/test.db"
  with DataConn(db) as conn:
    cursor = conn.cursor()

위 코드 에서 우 리 는 SQLite 데이터베이스 파일 을 가 져 오 는 경 로 를 만 들 었 습 니 다.enter__방법 은 자동 으로 실행 되 고 데이터베이스 연결 대상 을 되 돌려 줍 니 다.현재 우 리 는 데이터베이스 연결 대상 을 가 져 온 후에 커서 를 만들어 데이터베이스 에 데 이 터 를 기록 하거나 데이터 베 이 스 를 조회 합 니 다.우리 가 with 문 구 를 종료 할 때,그것 은 를 호출 합 니 다.exit__방법 은 이 연결 을 실행 하고 닫 는 데 사 용 됩 니 다.
컨 텍스트 관리 자 를 만 들 기 위해 다른 방법 을 사용 합 니 다.
2.2 contextlib 를 이용 하여 컨 텍스트 관리 자 를 만 듭 니 다.
Python 2.5 는 with 문 구 를 추가 할 뿐만 아니 라 contextlib 모듈 도 추가 합 니 다.컨 텍스트 lib 의 contextmanager 함 수 를 장식 기로 사용 하여 컨 텍스트 관리 자 를 만 들 수 있 습 니 다.파일 을 열 고 닫 는 데 사용 할 컨 텍스트 관리 자 를 만 들 려 고 시도 합 니 다.

from contextlib import contextmanager

@contextmanager
def file_open(path):
  try:
    f_obj = open(path,"w")
    yield f_obj
  except OSError:
    print("We had an error!")
  finally:
    print("Closing file")
    f_obj.close()

if __name__ == "__main__":
  with file_open("test/test.txt") as fobj:
    fobj.write("Testing context managers")
여기 서 contextlib 모듈 에서 contextmanager 를 도입 한 다음 에 우리 가 정의 하 는 file 을 장식 합 니 다.오픈 함수.이것 은 우리 가 Python 의 with 문 구 를 사용 하여 file 를 호출 할 수 있 도록 합 니 다.오픈 함수.함수 에서 우 리 는 파일 을 열 고 yield 를 통 해 전달 합 니 다.최종 메 인 함수 에서 사용 할 수 있 습 니 다.
with 구문 이 끝나 면 제어 가 file 로 돌아 갑 니 다.open 함수,yield 구문 뒤의 코드 를 계속 실행 합 니 다.이것 은 최종 적 으로 finally 문 구 를 실행 합 니 다.파일 을 닫 습 니 다.파일 을 열 때 OSError 오류 가 발생 하면 캡 처 되 고 최종 finally 문 구 는 파일 핸들 을 닫 습 니 다.
contextlib.closing(thing)
contextlib 모듈 은 매우 편리 한 도 구 를 제공 합 니 다.첫 번 째 도 구 는 closing 클래스 입 니 다.코드 블록 이 실행 되면 이 벤트 를 닫 습 니 다.Python 공식 문 서 는 다음 과 같은 예 시 를 보 여 주 었 습 니 다.

>>> from contextlib import contextmanager
>>> @contextmanager
... def closing(db):
...   try:
...     yield db.conn()
...   finally:
...     db.close()
이 코드 에서,우 리 는 contextmanager 에 포 함 된 닫 기 함 수 를 만 들 었 습 니 다.이것 은 closing 류 와 같다.차이 점 은 우리 가 with 구문 에서 장식 기 가 아 닌 closing 류 자 체 를 사용 할 수 있다 는 것 이다.다음 과 같은 예 를 보 여 주세요.

>>> from contextlib import closing
>>> from urllib.request import urlopen
>>> with closing(urlopen("http://www.google.com")) as webpage:
...   for line in webpage:
...     pass
이 예제 에서,우 리 는 closing 클래스 에서 url 웹 페이지 를 엽 니 다.우리 가 with 문 구 를 실행 하면 웹 페이지 를 가리 키 는 핸들 이 닫 힙 니 다.
contextlib.suppress(*exceptions)
또 다른 도 구 는 Python 3.4 에 추 가 된 suppress 류 입 니 다.이 상하 문 관리 도구 뒤의 이념 은 임의의 수의 이상 을 금지 할 수 있다 는 것 이다.만약 우리 가 FileNotFoundError 이상 을 무시 하고 싶다 면.만약 당신 이 아래 의 상하 문 관리 자 를 썼 다 면,그것 은 정상적으로 작 동 하지 않 을 것 이다.

>>> with open("1.txt") as fobj:
...   for line in fobj:
...     print(line)
...
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '1.txt'
보시 다시 피 이 컨 텍스트 관리 자 는 이 이상 을 처리 하지 않 았 습 니 다.이 오 류 를 무시 하고 싶다 면 다음 과 같은 방식 으로 할 수 있 습 니 다.

>>> from contextlib import suppress
>>> with suppress(FileNotFoundError):
...   with open("1.txt") as fobj:
...     for line in fobj:
...       print(line)
이 코드 에서 우 리 는 suppress 를 도입 한 다음 에 우리 가 무시 해 야 할 이상 을 전달 합 니 다.이 예 에서 FileNotFoundation Error 입 니 다.이 코드 를 실행 하려 면 파일 이 존재 하지 않 을 때 아무 일 도 일어나 지 않 았 고 오류 도 발생 하지 않 았 음 을 알 게 될 것 입 니 다.이 컨 텍스트 관리 자 는 다시 사용 할 수 있 으 며,2.4 장 은 구체 적 으로 설명 할 것 입 니 다.
contextlib.redirect_stdout/redirect_stderr
contextlib 모듈 은 표준 출력 과 표준 오류 출력 을 재 설정 하 는 도구 도 있 는데 각각 Python 3.4 와 3.5 에 추 가 됩 니 다.이 도구 들 이 가입 되 기 전에 표준 출력 에 대한 방향 을 바 꾸 려 면 다음 과 같은 방식 으로 조작 해 야 합 니 다.

import sys
path = "test/test.txt"

with open(path,"w") as fobj:
  sys.stdout = fobj
  help(sum)
contextlib 모듈 을 이용 하여 다음 과 같은 방식 으로 조작 할 수 있 습 니 다.

from contextlib import redirect_stdout

path = "test/test.txt"

with open(path,"w") as fobj:
  with redirect_stdout(fobj):
    help(redirect_stdout)
위의 두 가지 예 에서 우 리 는 모두 표준 출력 을 파일 로 재 설정 합 니 다.Python 의 help 함 수 를 호출 할 때 표준 출력 에 정 보 를 출력 하 는 것 이 아니 라 정 보 를 재 설정 한 파일 에 저장 합 니 다.표준 출력 을 캐 시 나 Tkinter 나 wxPython 같은 인터페이스 에서 가 져 온 파일 제어 형식 으로 바 꿀 수도 있 습 니 다.
2.3 ExitStack
ExitStack 은 컨 텍스트 관리자 로 다른 컨 텍스트 관리 와 쉽게 결합 하거나 지 울 수 있 습 니 다.이것 은 어떻게 들 으 면 사람 을 헷 갈 리 게 합 니까?우 리 는 Python 공식 문서 의 예 를 보 겠 습 니 다.아마도 우 리 는 그것 을 더욱 쉽게 이해 할 수 있 을 것 입 니 다.

>>> from contextlib import ExitStack
>>> filenames = ["1.txt","2.txt"]
>>> with ExitStack as stack:
...   file_objects = [stack.enter_context(open(filename)) for filename in filenames]
이 코드 는 목록 에 일련의 컨 텍스트 관리 자 를 만 드 는 것 입 니 다.ExitStack 은 레지스터 의 스 택 을 유지 합 니 다.우리 가 with 문 구 를 종료 하면 파일 이 닫 히 고 스 택 은 사진 을 거꾸로 찍 는 순서 로 컨 텍스트 관리 자 를 호출 합 니 다.
Python 공식 문서 에서 contextlib 에 관 한 예 가 많 습 니 다.다음 과 같은 기술 을 배 울 수 있 습 니 다.
  • 부터enter__방법 중 이상 포획
  • 부정 확 한 컨 텍스트 관리 자 를 지원 합 니 다
  • try-finally
  • 교체
  • 기타
  • 2.4 재 활용 가능 한 컨 텍스트 관리자
    대부분의 컨 텍스트 관리 자 는 with 구문 에서 만 사용 할 수 있 습 니 다.예제 는 다음 과 같 습 니 다.
    
    >>> from contextlib import contextmanager
    >>> @contextmanager
    ... def single():
    ...   print("Yielding")
    ...   yield
    ...   print("Exiting context manager")
    ...
    >>> context = single()
    >>> with context:
    ...   pass
    ...
    Yielding
    Exiting context manager
    >>> with context:
    ...   pass
    ...
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
     File "/usr/lib/python3.4/contextlib.py", line 61, in __enter__
      raise RuntimeError("generator didn't yield") from None
    RuntimeError: generator didn't yield
    이 코드 에서 우 리 는 컨 텍스트 관리자 인 스 턴 스 를 만 들 고 Python 의 with 구문 에서 두 번 실행 하려 고 시도 합 니 다.두 번 째 로 실 행 될 때,그것 은 Runtime Error 를 던 졌 다.
    그런데 만약 에 저희 가 상하 문 관리 자 를 두 번 실행 하고 싶다 면 요?재 활용 가능 한 컨 텍스트 관리 자 를 사용 해 야 합 니 다.전에 사 용 했 던 redirect 를 사용 합 시다.stdout 이 컨 텍스트 관리 자 를 예제 로 합 니 다.
    
    >>> from contextlib import redirect_stdout
    >>> from io import StringIO
    >>> stream = StringIO()
    >>> write_to_stream = redirect_stdout(stream)
    >>> with write_to_stream:
    ...   print("Write something to the stream")
    ...   with write_to_stream:
    ...     print("Write something else to stream")
    ...
    >>> print(stream.getvalue())
    Write something to the stream
    Write something else to stream
    이 코드 에서 우 리 는 컨 텍스트 관리 자 를 만 들 었 습 니 다.모두 StringIO(메모리 의 파일 흐름)에 데 이 터 를 기록 합 니 다.이 코드 는 이전 처럼 Runtime Error 오 류 를 던 지지 않 고 정상적으로 작 동 합 니 다.그 이 유 는 redirect 입 니 다.stdout 은 다시 사용 할 수 있 습 니 다.두 번 호출 할 수 있 습 니 다.물론 실제 예 는 더 많은 함수 호출 이 있 고 더욱 복잡 할 것 이다.다시 사용 할 수 있 는 컨 텍스트 관리자 가 반드시 스 레 드 가 안전 한 것 은 아니 므 로 주의해 야 합 니 다.스 레 드 에서 사용 할 필요 가 있다 면 Python 문 서 를 자세히 읽 으 십시오.
    2.5 총화
    문맥 관리 자 는 재 미 있 고 편리 합 니 다.나 는 대 화 를 열 고 닫 는 등 자동 테스트 에서 자주 사용한다.이제 Python 에 내 장 된 도 구 를 사용 하여 컨 텍스트 관리 자 를 만 들 수 있 을 것 입 니 다.contextlib 에 관 한 파 이 썬 의 문 서 를 계속 읽 을 수 있 습 니 다.그곳 에는 본문 이 덮어 쓰 지 않 은 지식 이 많 습 니 다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기