Python 의 컨 텍스트 관리자 와 else 블록 을 깊이 학습 합 니 다.

머리말
본 고 는 주로 Python 컨 텍스트 관리자 와 else 블록 에 관 한 내용 을 소개 하고 참고 학습 을 제공 합 니 다.다음은 더 이상 말 하지 않 겠 습 니 다.상세 한 소 개 를 해 보 겠 습 니 다.
시작 하기 전에 다음 말 을 살 펴 보 자.
결국 컨 텍스트 관리 자 는 서브루틴 자체 만큼 중요 할 수 있 습 니 다.현재,우 리 는 컨 텍스트 관리자 의 모피 만 알 고 있 습 니 다.Basic 언어 는 with 문구 가 있 고,많은 언어 가 있 습 니 다.그러나 각종 언어 에서 with 문장의 역할 이 다 르 고 간단 한 일 을 합 니 다.점 호 를 계속 사용 하여 속성 을 찾 는 것 을 피 할 수 있 지만 일 하기 전에 준비 하고 사후 청 소 를 하지 않 습 니 다.이름 이 같다 고 생각 하지 마라,작용 도 같다 는 것 을 의미한다.with 문 구 는 매우 일어나 지 않 는 특성 이다.
――Raymond Hettinger
웅변 적 인 파 이 썬 보도 자
이것 을 먼저 하고 저것 을 하 세 요:if 문장 이외 의 else 블록
이 언어 특성 은 비밀 은 아니 지만 중시 되 지 않 았 다.else 자 구 는 if 구문 뿐만 아니 라 for,while,try 구문 에서 도 사용 할 수 있다.for/else,while/else 와 try/else 의 의미 관 계 는 밀접 하지만 if/else 와 차이 가 크다.처음에 else 라 는 단어의 뜻 은 이러한 특성 에 대한 이 해 를 방해 하 였 으 나 결국 나 는 습관 이 되 었 다.
else 자구 의 행동 은 다음 과 같다.
for
for 순환 이 끝 났 을 때 만(즉,for 순환 이 break 구문 에 의 해 중단 되 지 않 았 음)else 블록 을 실행 합 니 다.
while
while 순환 이 가짜 값 으로 종료 되 었 을 때(즉,while 순환 이 break 구문 에 의 해 중단 되 지 않 았 음)else 블록 을 실행 합 니 다.
try
try 블록 에 이상 이 없 을 때 만 else 블록 을 실행 합 니 다.공식 문서https://docs.python.org/3/reference/compound_stmts.html는 또"else 자구 가 던 진 이상 은 앞의 except 자구 로 처리 되 지 않 는 다"고 지적 했다.
주의:
모든 상황 에서 이상 하거나 return,break 또는 continue 문 구 를 통 해 제어 권 이 복합 문장의 메 인 블록 밖으로 넘 어가 면 else 자구 도 건 너 뜁 니 다.
이 문장 들 에서 else 자 구 를 사용 하면 코드 를 쉽게 읽 을 수 있 고 번 거 로 움 을 줄 일 수 있 으 며 제어 표 지 를 설정 하거나 추가 적 인 if 문 구 를 추가 하지 않 아 도 된다.
다음 코드 세 션 과 같이 else 자 구 를 순환 적 으로 사용 합 니 다.

 for item in my_list:
  if item.flavor == 'banana':
   break
  else:
   raise ValueError('No banana flavor found!')
처음에는 try/except 블록 에서 else 자 구 를 사용 할 필요 가 없다 고 생각 했 을 수도 있 습 니 다.결국 다음 코드 세 션 에서dangerous_call()이상 을 던 지지 않 고after_call() 만 실 행 될 수 있 습 니 다.그 렇 죠?

 try:
  dangerous_call()
  after_call()
 except OSError:
  log('OSError...')
그러나after_call() try 블록 에 넣 어 서 는 안 됩 니 다.뚜렷 하고 정확 하기 위해 서 는 try 블록 에서 예상 치 못 한 문구 만 던 져 야 합 니 다.그래서 아래 처럼 쓰 는 것 이 좋다.

 try:
  dangerous_call()
 except OSError:
  log('OSError...')
 else:
  after_call()
트 리 블록 수 비 는dangerous_call()발생 할 수 있 는 오류 가 아니 라after_call()임 이 분명 하 다.그리고 try 블록 이 이상 을 던 지지 않 아야 실행 할 수 있 음 이 분명 하 다after_call().
컨 텍스트 관리자 와 with 블록
컨 텍스트 관리자 대상 이 존재 하 는 목적 은 with 문 구 를 관리 하 는 것 입 니 다.마치 교체 기의 존재 가 for 문 구 를 관리 하기 위 한 것 과 같 습 니 다.
with 문장의 목적 은 try/finally 모델 을 간소화 하 는 것 이다.이 모드 는 코드 가 실 행 된 후에 특정한 작업 을 수행 하도록 하 는 데 사 용 됩 니 다.그 코드 가 이상,return 구문 또는sys.exit() 호출 로 중단 되 더 라 도 지정 한 작업 을 수행 합 니 다.finally 자구 의 코드 는 보통 중요 한 자원 을 방출 하거나 임시 변 경 된 상 태 를 복원 하 는 데 사 용 됩 니 다.
컨 텍스트 관리자 프로 토 콜 포함enter__ 와exit__ 두 가지 방법.with 문장 이 실 행 될 때,상하 문 관리자 대상 에서 를 호출 합 니 다enter__ 방법with 구문 실행 이 끝나 면 컨 텍스트 관리자 대상 에서 호출 합 니 다.exit__ 방법 은 이것으로 finally 자구 의 역할 을 한다.
🌰 파일 대상 을 컨 텍스트 관리자 로 사용 하 는 것 을 보 여 줍 니 다.

>>> with open('mirror.py') as fp: # fp         ,     __enter__    self
...   src = fp.read(60) #  fp       
...
>>> len(src)
>>> fp # fp        
<_io.TextIOWrapper name='mirror.py' mode='r' encoding='UTF-8'>
>>> fp.closed, fp.encoding #     fp     
(True, 'UTF-8')
>>> fp.read(60) #      fp   I/O  ,   with    ,   TextIOWrappper.__exit__        
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
Looking Glass 컨 텍스트 관리자 클래스 테스트

>>> from mirror import LookingGlass
>>> with LookingGlass() as what: #        LookingGlass    ;Python          __enter__  ,        what 
...  print('Alice, Kitty and Snowdrop') #        ,    what    
...  print(what)
...
pordwonS dna yttiK ,ecilA #           
YKCOWREBBAJ
>>> what #   ,with       ,    ,__enter__      ,    what         'JABBERWOCKY'
'JABBERWOCKY'
>>> print('Back to normal.') #          
Back to normal.
mirror.py:Looking Glass 컨 텍스트 관리자 류 의 코드

class LookingGlass:

 def __enter__(self):      #    self   ,Python  __enter__          
  import sys
  self.original_write = sys.stdout.write #      sys.stdout.write             ,     
  sys.stdout.write = self.reverse_write #   sys.stdout.write      ,          
  return 'JABBERWOCKY'     #    'JABBERWOCKY'    ,             what

 def reverse_write(self, text):    #        sys.stdout.write    ,  text        ,           
  return self.original_write(text[::-1])


 def __exit__(self, exc_type, exc_val, traceback): #       ,Python   __exit__          None,      ,           
  import sys
  sys.stdout.write = self.original_write #       sys.studout.write  
  if exc_type is ZeroDivisionError:  #      ,    ZeroDivisionError   ,      
   print('Please DO NOT divide by zero!') 
   return True       #      True,     ,      
해석 기 호출enter__ 방법 은 암시 적 인 self 를 제외 하고 어떠한 인자 도 들 어 오지 않 습 니 다.전달exit__ 방법의 세 가지 매개 변 수 는 다음 과 같다.
exc_type
이상 클래스(예:ZeroDivisionError)
exc_value
예외 실례.때때로 매개 변수 가 이상 구조 방법 에 전 달 될 수 있 습 니 다.예 를 들 어 오류 메시지 등 매개 변 수 는 exc 를 사용 할 수 있 습 니 다.value.args 가 져 오기
traceback
traceback 대상
with 블록 외 에 Looking Glass 클래스 를 사용 합 니 다.

>>> from mirror import LookingGlass
>>> manager = LookingGlass() #       manager  ,    with LookingGlass() as manager
>>> manager
<mirror.LookingGlass object at 0x2a578ac>
>>> monster = manager.__enter__() #           __enter__()  ,      monster 
>>> monster == 'JABBERWOCKY' # monster      'JABBERWOCKY',     True      ,        
eurT
>>> monster
'YKCOWREBBAJ'
>>> manager
>ca875a2x0 ta tcejbo ssalGgnikooL.rorrim<
>>> manager.__exit__(None, None, None) #   manager.__exit__,      stdout.write
>>> monster
'JABBERWOCKY'
contextlib 모듈 의 유 틸 리 티 도구
closing
대상 이close()방법 을 제 공 했 지만 실현 되 지 않 았 다 면enter__/__exit__ 프로 토 콜,그러면 이 함 수 를 사용 하여 상하 문 관리 자 를 구축 할 수 있 습 니 다.
suppress
지정 한 이상 을 임시로 무시 하 는 컨 텍스트 관리 자 를 만 듭 니 다.
@contextmanager
이 장식 기 는 간단 한 생 성기 함 수 를 컨 텍스트 관리자 로 바 꾸 어 관리자 프로 토 콜 을 만 들 지 않 아 도 됩 니 다.
ContextDecorator
클래스 기반 컨 텍스트 관리 자 를 정의 하 는 기본 클래스 입 니 다.이 컨 텍스트 관리 자 는 장식 함수 에 도 사용 되 며 관 리 된 컨 텍스트 에서 전체 함 수 를 실행 할 수 있 습 니 다.
ExitStack
이 컨 텍스트 관리 자 는 여러 컨 텍스트 관리자 에 들 어 갈 수 있 습 니 다.with 블록 이 끝 났 을 때 ExitStack 은 스 택 의 각 컨 텍스트 관리자 의 를 후진 선 출 순서에 따라 호출 합 니 다.exit__ 방법with 블록 이 몇 개의 컨 텍스트 관리자 에 들 어 가 는 지 미리 몰 랐 다 면 이 종 류 를 사용 할 수 있 습 니 다.예 를 들 어 임의의 파일 목록 에 있 는 모든 파일 을 동시에 엽 니 다.
@contextmanager 사용 하기
@contextmanager 장식 기 는 컨 텍스트 관리 자 를 만 드 는 모델 코드 의 양 을 줄 일 수 있 습 니 다.완전한 클래스 를 만 들 지 않 아 도 되 기 때문에 을 정의 합 니 다.enter__ 와exit__ 방법,하나의 yield 문 구 를 가 진 생 성 기 를 실현 하여enter__ 방법 반환 값.
@contextmanager 장식 을 사용 하 는 생 성기 에서 yield 문 구 는 함수 의 정의 체 를 두 부분 으로 나 누 는 역할 을 합 니 다.yield 문 앞 에 있 는 모든 코드 가 with 블록 에서 시 작 될 때(즉 해석 기 호출enter__ 방법 시)실행,yield 문장 뒤의 코드 는 with 블록 이 끝 날 때(즉 호출exit__ 방법 시)집행.
mirror_gen.py:생 성 기 를 사용 한 컨 텍스트 관리자

import contextlib


@contextlib.contextmanager    #    contextmanager    
def looking_glass():
 import sys
 original_write = sys.stdout.write #       sys.stdout.write   

 def reverse_write(text):   #        reverse_write   ;         original_write
  original_write(text[::-1])

 sys.stdout.write = reverse_write #   sys.stdout.write     reverse_write
 yield 'JABBERWOCKY'     #      ,        with     as         
 sys.stdout.write = original_write #         with  ,     yield        ;          sys. stdout.write   

with looking_glass() as what:   #             with   
 print('Alice, Kitty and Snowdrop')
 print(what)

print(what)
상기 코드 가 실 행 된 결 과 는 다음 과 같 습 니 다.

pordwonS dna yttiK ,ecilA
YKCOWREBBAJ
JABBERWOCKY
사실 contextlib.contextmanager 장식 기 는 함 수 를 실현 로 포장 합 니 다.enter__ 와exit__ 방법의 종류
이런 종류의enter__ 방법 은 다음 과 같은 작용 을 한다.
(1)생 성기 함 수 를 호출 하여 생 성기 대상 을 저장 합 니 다(여기 서 gen 이 라 고 합 니 다).
(2)next(gen)를 호출 하여 yield 키워드 가 있 는 위치 로 실행 합 니 다.
(3)next(gen)에서 나 온 값 을 with/as 문장의 목표 변수 에 연결 할 수 있 도록 되 돌려 줍 니 다.
with 블록 종료 시,exit__ 방법 은 다음 과 같은 몇 가지 일 을 할 것 이다.
(1)이상 을 exc 에 게 전 달 했 는 지 확인type;있 으 면 호출gen.throw(exception) ,생 성기 함수 정의 체 에 yield 키 워드 를 포함 하 는 줄 에 이상 을 던 집 니 다.
(2)그렇지 않 으 면 호출next(gen) ,생 성기 함수 정의 체 에서 yield 문 구 를 계속 실행 합 니 다.
주의:
위의🌰 심각 한 오류 가 있 습 니 다.with 블록 에 이상 을 던 지면 Python 해석 기 가 잡 아서 lookingglass 함수 의 yield 표현 식 에서 다시 던 집 니 다.하지만 잘못된 코드 가 처리 되 지 않 았 기 때문에 lookingglass 함수 가 중단 되 어 원래 의sys.stdout.write 방법 으로 영원히 회복 되 지 못 해 시스템 이 무효 상태 에 있 습 니 다.
mirror_gen_exc.py:생 성 기 를 기반 으로 한 컨 텍스트 관리자 이 며 이상 처 리 를 실현 합 니 다.

import contextlib


@contextlib.contextmanager
def looking_glass():
 import sys
 original_write = sys.stdout.write

 def reverse_write(text):
  original_write(text[::-1])

 sys.stdout.write = reverse_write
 msg = ''        #      ,             ;
 try:
  yield 'JABBERWOCKY'
 except ZeroDivisionError:    #   ZeroDivisionError   ,        
  msg = 'Please DO NOT divide by zero!'
 finally:
  sys.stdout.write = original_write #     sys.stdout.write          
  if msg:
   print(msg)      #          ,      
주의:
@contextmanager 장식 기 를 사용 할 때 yield 문 구 를 try/finally 구문 에 넣 거나 with 구문 에 넣 는 것 은 피 할 수 없습니다.컨 텍스트 관리자 의 사용자 가 with 블록 에서 무엇 을 할 지 영원히 모 르 기 때 문 입 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기