Python 컨텍스트 관리자

PythonBeginner
지금 연습하기

소개

Python 의 컨텍스트 관리자 (context managers) 는 널리 사용되지만, 그 사용 목적을 이해하는 사람은 많지 않습니다. 파일 읽기 및 쓰기와 같이 흔히 사용되는 이 구문들은 특정 리소스가 특정 프로세스에서만 사용되도록 보장함으로써 애플리케이션이 시스템 메모리를 보존하고 리소스 관리를 개선하도록 돕습니다.

본 랩에서는 with 문을 사용하여 자동 리소스 관리를 수행하는 방법을 배우고, 이어서 두 가지 다른 방법, 즉 함수 기반 접근 방식과 클래스 기반 접근 방식을 사용하여 자신만의 컨텍스트 관리자를 생성해 볼 것입니다.

with 문

이 단계에서는 파일 객체와 같은 컨텍스트 관리자 (context manager) 와 함께 with 문을 사용하는 방법을 배웁니다. 컨텍스트 관리자는 코드 블록 (컨텍스트) 이 시작되고 끝날 때 알림을 받는 객체입니다. with 문은 이 알림 프로세스를 자동으로 처리합니다.

예를 들어, 파일 객체는 컨텍스트 관리자입니다. with 블록이 끝나면 블록 내에서 오류가 발생하더라도 파일 객체가 자동으로 닫힙니다. 이는 데이터 손실과 리소스 누수를 방지합니다.

참고: WebIDE(VS Code 와 유사) 사용에 익숙하지 않다면, 이 랩에서 먼저 학습하십시오.

실제로 어떻게 작동하는지 살펴보겠습니다. 왼쪽에 있는 파일 탐색기에서 main.py 파일을 엽니다. 다음 코드를 복사하여 붙여넣으십시오. 이 코드는 with 문을 사용하여 파일을 생성하고 내용을 작성한 다음, 그 내용을 읽을 것입니다.

## 'with' 문을 시연하기 위해 파일을 생성할 것입니다.
## 먼저, 파일에 일부 내용을 작성해 보겠습니다.
with open('my_file.txt', 'w') as f:
    f.write('This is a test file.')

## 이제 컨텍스트 관리자를 사용하여 다시 읽어 보겠습니다.
## 'with' 블록을 벗어나면 파일이 자동으로 닫힙니다.
with open('my_file.txt') as f:
    file_contents = f.read()
    print(file_contents)

## 오류가 발생하더라도 파일은 여기서 자동으로 닫힙니다.
print("\nFile has been read and closed.")

이제 터미널에서 스크립트를 실행하여 출력을 확인하십시오.

python3 main.py

파일 쓰기 및 읽기가 성공적으로 완료되었음을 확인하는 다음 출력을 보게 될 것입니다. with 문은 쓰기 및 읽기 작업 후에 my_file.txt가 올바르게 닫히도록 보장합니다.

This is a test file.

File has been read and closed.

with 문을 사용하는 것은 파일이나 네트워크 연결과 같은 리소스를 처리하는 권장되는 방법입니다. 코드가 더 깔끔하고 안전해지기 때문입니다.

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

이 단계에서는 제너레이터 함수와 @contextlib.contextmanager 데코레이터를 사용하여 사용자 정의 컨텍스트 관리자를 만드는 방법을 알아봅니다. 이는 간단한 컨텍스트 관리자를 만드는 간결한 방법입니다.

yield 문 앞의 코드는 with 블록에 진입할 때 실행되며 (설정 로직), yield 문 뒤의 코드는 블록을 나갈 때 실행됩니다 (정리 로직). yield된 값은 with 문에서 as 키워드를 사용하여 변수에 할당될 수 있습니다.

파일 탐색기에서 function_cm.py 파일을 엽니다. 다음 코드를 파일에 복사합니다.

## contextlib 데코레이터를 사용한 함수 기반 컨텍스트 관리자
import contextlib

@contextlib.contextmanager
def context_manager(num):
    print('Enter')  ## yield 이전 코드는 __enter__에서 실행됨
    yield num + 1   ## yield 된 값이 'cm' 변수가 됨
    print('Exit')    ## yield 이후 코드는 __exit__에서 실행됨

with context_manager(2) as cm:  ## cm 은 yield 된 값 (3) 을 받음
    print('Right in the middle with cm = {}'.format(cm))

이제 터미널에서 스크립트를 실행합니다.

python3 function_cm.py

다음 출력을 보게 될 것입니다. 실행 순서에 유의하세요. yield 이전 코드가 먼저 실행되고, 그 다음 with 블록 내부 코드가 실행되며, 마지막으로 yield 이후 코드가 실행됩니다.

Enter
Right in the middle with cm = 3
Exit

이 접근 방식은 데이터베이스 연결 설정 및 해제 또는 설정을 일시적으로 변경하는 것과 같이 임시 컨텍스트를 생성하는 데 매우 유용합니다.

클래스 기반 컨텍스트 관리자

이 단계에서는 클래스로 컨텍스트 관리자를 구현하는 방법을 알아봅니다. 이 접근 방식은 더 많은 제어 권한을 제공하며 더 복잡한 시나리오에 적합합니다. 클래스 기반 컨텍스트 관리자를 생성하려면 두 가지 특별한 메서드인 __enter__와 __exit__를 정의해야 합니다.

  • __enter__: with 문에 진입할 때 호출되는 메서드입니다. 설정 로직 (setup logic) 을 수행해야 합니다. 반환 값은 as 뒤에 변수가 제공된 경우 해당 변수에 할당됩니다.
  • __exit__: with 블록을 정상적으로 또는 예외로 인해 종료할 때 호출되는 메서드입니다. 정리 로직 (cleanup logic) 을 수행해야 합니다.

하나를 만들어 보겠습니다. class_cm.py 파일을 열고 다음 코드를 복사하여 붙여넣으세요.

## 클래스 기반 컨텍스트 관리자: __enter__ 및 __exit__ 메서드 구현
class ContextManager:
    def __enter__(self, *args, **kwargs):  ## 'with' 블록 진입 시 호출됨
        print("--enter--")
        return self  ## 'as' 변수로 사용할 객체를 반환할 수 있음

    def __exit__(self, *args):  ## 'with' 블록 종료 시 호출됨
        print("--exit--")

with ContextManager():  ## __enter__ 호출 후, 완료되면 __exit__ 호출
    print("test")

터미널에서 스크립트를 실행합니다.

python3 class_cm.py

출력은 제어 흐름을 보여줍니다. __enter__ 메서드가 먼저 호출되고, 그 다음 with 블록 내부 코드가 실행되며, 마지막으로 정리 작업을 위해 __exit__ 메서드가 호출됩니다.

--enter--
test
--exit--

클래스 기반 접근 방식은 복잡한 설정 및 해제 로직을 단일 재사용 가능한 객체 내에 캡슐화할 수 있으므로 강력합니다.

요약

실습을 완료하신 것을 축하드립니다! Python 에서 컨텍스트 관리자를 사용하여 리소스를 효과적으로 관리하는 방법을 배웠습니다.

안전한 파일 처리를 위한 일반적인 with 문으로 시작했습니다. 그런 다음 두 가지 다른 방법을 사용하여 자신만의 사용자 정의 컨텍스트 관리자를 만드는 방법을 익혔습니다.

  • 간단한 설정 및 해제 작업에 유용한 @contextlib.contextmanager 데코레이터를 사용한 함수 기반 접근 방식.
  • 더 복잡한 리소스 관리에 이상적인 __enter__ 및 __exit__ 메서드를 구현하는 클래스 기반 접근 방식.

이러한 기술은 리소스를 적절하게 처리하는 깔끔하고 안정적이며 효율적인 Python 코드를 작성하는 데 매우 중요합니다.