@contextmanager , @wraps

Leejaegun·2025년 1월 26일

Python & etc

목록 보기
12/27

1. @contextmanager

@contextmanager"뒷바라지 코드"라고 생각하면 이해하기 쉽습니다.
yield를 기준으로 앞 부분은 사전 작업, 뒷 부분은 사후 작업을 처리합니다.
이로써, 리소스 관리를 더 간결하고 안전하게 처리할 수 있습니다.

동작 원리

  1. yield 앞쪽: 사전 작업(리소스 설정, 파일 생성 등)
  2. yield 뒤쪽: 사후 작업(리소스 정리, 파일 닫기 등)
  3. 주로 try ~ except ~ finally 구조와 함께 사용되어 안정성을 높입니다.
  4. 선언한 함수는 with 문과 함께 사용됩니다.

example

from contextlib import contextmanager
import os

@contextmanager
def write_open(path):
    # 사전 작업: 디렉토리가 없으면 생성
    dir_name = os.path.dirname(path)
    if not os.path.isdir(dir_name):
        os.makedirs(dir_name, exist_ok=True)

    # 사전 작업: 파일 열기
    fw = open(path, "w")
    print(1)  # 디버깅용 출력
    try:
        yield fw  # 메인 동작 부분
    finally:
        # 사후 작업: 파일 닫기
        fw.close()
        print(3)  # 디버깅용 출력
with write_open("ns/log.txt") as f:
    print(2)  # 메인 동작 부분
    f.write("Hello world")
print(4)

출력하면
1
2
3
4

해석: 폴더가 없으면 만드는것은 그냥 메인이랑 벗어나므로 뒤에 숨기고(contextmanager) 메인에 집중하도록 하는 것입니다.

wraps

@wraps함수의 동작은 그대로 유지하면서, 함수의 겉모습(메타데이터)을 바꾸는 데 사용됩니다.
주로 데코레이터를 작성할 때 사용되며, 원래 함수의 이름, 문서 문자열(docstring), 기타 속성을 유지합니다.

동작 원리

데코레이터를 사용하면 함수의 이름과 문서 문자열이 변경될 수 있습니다.
@wraps를 사용하면 원래 함수의 이름과 문서 문자열을 유지하여 코드의 가독성과 디버깅 편의성을 높입니다.

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Wrapper starts")
        result = func(*args, **kwargs)
        print("Wrapper ends")
        return result
    return wrapper

@my_decorator
def say_hello():
    """This function says hello."""
    print("Hello, world!")

say_hello()
print(say_hello.__name__)  # 함수 이름 출력
print(say_hello.__doc__)   # 함수 문서 문자열 출력

#출력
Wrapper starts
Hello, world!
Wrapper ends
say_hello
This function says hello.

해석

  • @wraps를 사용하지 않으면 함수 이름과 문서 문자열이 데코레이터의 내부 함수로 덮어쓰기됩니다.
  • @wraps를 사용하면 원래 함수의 메타데이터(이름, docstring 등)를 유지할 수 있습니다.
profile
Lee_AA

0개의 댓글