본문 바로가기

언어/Python

[ Python ] 함수를 객체로 다루어 디버깅에 사용하기 (profiling)

반응형

파이썬에서 함수는 일급 객체(First-Class Object)로 취급됩니다. 이는 함수가 변수에 할당되거나, 다른 함수의 인수로 전달되거나, 함수에서 반환될 수 있다는 의미입니다. 이러한 특성을 활용하면 함수 디버깅과 프로파일링을 쉽게 수행할 수 있습니다. 디버깅과 프로파일링을 위한 다양한 방법을 소개합니다.

1. 기본 디버깅

기본 디버깅 방법은 함수의 동작을 확인하기 위해 출력문(print())을 사용하거나, 내장 디버거(pdb)를 사용하는 것입니다.

출력문을 이용한 디버깅

def example_function(x):
    print(f"Input: {x}")
    result = x * 2
    print(f"Output: {result}")
    return result

example_function(5)

pdb를 이용한 디버깅

import pdb

def example_function(x):
    pdb.set_trace()
    result = x * 2
    return result

example_function(5)

위 코드는 example_function을 호출할 때 중단점을 설정하고, 함수 내부에서 변수 값을 실시간으로 확인할 수 있게 해줍니다.

2. 함수 데코레이터를 이용한 디버깅

데코레이터를 사용하면 특정 함수의 실행 전후로 추가적인 작업을 수행할 수 있습니다. 이를 활용하여 함수 호출 시 입력과 출력을 기록하거나, 실행 시간을 측정할 수 있습니다.

입력과 출력 기록

def debug_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned: {result}")
        return result
    return wrapper

@debug_decorator
def example_function(x):
    return x * 2

example_function(5)

실행 시간 측정

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
        return result
    return wrapper

@timing_decorator
def example_function(x):
    return x * 2

example_function(5)

3. 프로파일링

프로파일링은 코드의 성능을 분석하는 작업으로, 주로 함수 호출 횟수와 실행 시간을 측정합니다. 파이썬에서는 cProfile 모듈을 사용하여 프로파일링을 수행할 수 있습니다.

cProfile을 이용한 프로파일링

import cProfile

def example_function(x):
    return x * 2

def main():
    for i in range(1000):
        example_function(i)

cProfile.run('main()')

결과 분석

cProfile.run()은 함수 호출 횟수, 총 실행 시간, 호출당 평균 실행 시간 등을 출력합니다. 결과를 더 잘 분석하기 위해 pstats 모듈을 사용할 수도 있습니다.

import cProfile
import pstats

def example_function(x):
    return x * 2

def main():
    for i in range(1000):
        example_function(i)

# 프로파일링 실행 및 결과 저장
cProfile.run('main()', 'profile_output')

# 저장된 결과 분석
p = pstats.Stats('profile_output')
p.strip_dirs().sort_stats('cumulative').print_stats(10)

4. functools의 wraps를 이용한 데코레이터

데코레이터를 사용할 때, functools.wraps를 사용하여 원래 함수의 메타데이터를 유지할 수 있습니다.

from functools import wraps

def debug_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned: {result}")
        return result
    return wrapper

@debug_decorator
def example_function(x):
    return x * 2

print(example_function.__name__)  # example_function

5. 요약

파이썬에서 함수는 일급 객체로 취급되므로, 함수 디버깅과 프로파일링을 위한 다양한 기법을 사용할 수 있습니다. 출력문, pdb를 통한 기본 디버깅부터 데코레이터와 cProfile을 통한 고급 디버깅 및 프로파일링 기법까지 다양한 방법을 통해 코드를 분석하고 최적화할 수 있습니다. 이를 통해 코드의 성능과 정확성을 높일 수 있습니다.

반응형