[Python] pdb, breakpoint(), 디버깅 도구
정의
pdb는 Python 표준 라이브러리의 대화형 디버거. 중단점, 스텝 실행, 변수 검사, 콜 스택 탐색을 제공. 3.7+ breakpoint() 빌트인이 표준 진입점.
breakpoint()
def process(items):
for i, item in enumerate(items):
breakpoint() # 여기서 디버거 진입
result = transform(item)
breakpoint() 호출 지점에서 pdb 시작. 다른 디버거(ipdb, pudb, debugpy)를 쓰려면 환경변수.
PYTHONBREAKPOINT=ipdb.set_trace python script.py
PYTHONBREAKPOINT=0 python script.py # 모든 breakpoint 비활성화 (프로덕션)
PYTHONBREAKPOINT=0은 코드를 안 고치고 디버깅 비활성화. 배포 환경 유용.
pdb 핵심 명령어
| 명령 | 동작 |
|---|---|
h | 도움말 |
l | 현재 줄 주변 코드 표시 |
ll | 함수 전체 |
n | 다음 줄 (step over) |
s | step into (함수 안으로) |
r | step out (함수 끝까지) |
c | continue (다음 중단점까지) |
j N | jump to line N |
p expr | 표현식 출력 |
pp expr | pretty print |
w | where (콜 스택) |
u | up (호출자로) |
d | down (호출 받은 곳으로) |
b 42 | line 42에 중단점 |
b foo.py:42 | 특정 파일/줄 |
b func_name | 함수 진입 시 |
b 42, x > 0 | 조건부 중단점 |
cl | 모든 중단점 제거 |
cl 1 | 1번 중단점 제거 |
q | 종료 |
interact | 인터프리터 모드 진입 |
예제 세션
def divide(a, b):
breakpoint()
return a / b
divide(10, 0)
> script.py(3)divide()
-> return a / b
(Pdb) l
1 def divide(a, b):
2 breakpoint()
3 -> return a / b
4
5 divide(10, 0)
(Pdb) p a, b
(10, 0)
(Pdb) p a / b
*** ZeroDivisionError: division by zero
(Pdb) w
script.py(5)<module>()
> script.py(3)divide()
(Pdb) q
사후 디버깅 (post-mortem)
예외 후 디버거 진입.
import pdb
try:
risky()
except:
pdb.post_mortem() # 예외 발생 지점에서 시작
또는 CLI:
python -m pdb script.py # 시작부터
python -m pdb -c continue script.py # 첫 예외에서 정지
조건부 중단점
(Pdb) b 42, x > 100 and y is None
루프 안에서 특정 조건 만족 시만 정지. 1000회 반복 중 1번을 찾을 때 유용.
표현식 모니터링: display
(Pdb) display x
(Pdb) display
(Pdb) n
display x: 5 [old: 4]
매 step마다 값 변화 자동 표시.
ipdb: IPython 기반
pip install ipdb
import ipdb; ipdb.set_trace()
# 또는
PYTHONBREAKPOINT=ipdb.set_trace python script.py
자동 완성, 색상, 더 풍부한 출력. 개발 환경에 추천.
pudb: 풀스크린 TUI
pip install pudb
import pudb; pu.db # 트레이스 시작
PYTHONBREAKPOINT=pudb.set_trace python script.py
vim 스타일 단축키, 콜 스택·변수·코드 동시 표시. 본격 디버깅에 강력.
debugpy: VS Code, PyCharm
IDE 디버거의 백엔드.
pip install debugpy
import debugpy
debugpy.listen(5678)
debugpy.wait_for_client() # 디버거 연결 대기
debugpy.breakpoint()
VS Code에서 attach configuration으로 연결. 원격 디버깅, 컨테이너 안 등에 유용.
faulthandler: 크래시 분석
세그폴트, 무한 루프 등 인터프리터 종료 시 트레이스 출력.
import faulthandler
faulthandler.enable() # SIGSEGV, SIGFPE 등 발생 시 트레이스
또는 시작 시:
python -X faulthandler script.py
PYTHONFAULTHANDLER=1 python script.py
크래시 위치를 파악하는 유일한 방법인 경우 있음.
traceback
import traceback
try:
work()
except Exception:
traceback.print_exc() # stderr로
traceback.print_exception(*sys.exc_info())
s = traceback.format_exc() # 문자열로
# 콜 스택 (예외 없이도)
traceback.print_stack()
로깅과 결합하면 무엇이 어디서 깨졌는지 파일에 저장 가능.
sys.settrace: 커스텀 트레이서
import sys
def tracer(frame, event, arg):
print(event, frame.f_code.co_name, frame.f_lineno)
return tracer
sys.settrace(tracer)
my_function()
sys.settrace(None)
이벤트: call, line, return, exception. 디버거·프로파일러 작성의 기반.
자주 보는 디버깅 패턴
빠른 진입
# 코드 안 어디서나
import pdb; pdb.set_trace()
# 또는 (3.7+)
breakpoint()
쓴 다음 즉시 잊지 말 것. 프로덕션 푸시 전 grep으로 확인.
print 디버깅의 단계적 진화
print(x)- 가장 빠름, 좋은 단서logger.debug("x=%s", x)- 로그 시스템 활용breakpoint()- 정말 복잡할 때- IDE 디버거 - 인스펙터, 조건부 중단점
print는 절대 부정적인 게 아님. 빠른 가설 검증에 효율적.
의심 함수 추적
def trace(fn):
import functools
@functools.wraps(fn)
def wrapper(*args, **kwargs):
print(f"-> {fn.__name__}({args}, {kwargs})")
result = fn(*args, **kwargs)
print(f"<- {fn.__name__} = {result!r}")
return result
return wrapper
@trace
def suspect(x): ...
또는 icecream 라이브러리:
pip install icecream
from icecream import ic
ic(x, y) # 변수명 + 값 자동 출력
무한 루프 / 행 (hang)
py-spy dump --pid 12345 # 현재 모든 스레드 스택
또는 SIGUSR1 시그널로 트레이스 덤프 (faulthandler.register).
import faulthandler, signal
faulthandler.register(signal.SIGUSR1)
# kill -USR1 <pid> 으로 트레이스 출력
함정
1. breakpoint() 푸시
def process():
breakpoint() # 프로덕션에 푸시되면 서버 정지
→ pre-commit hook으로 차단.
# .pre-commit-config.yaml
- id: no-breakpoint
name: Check no breakpoint()
entry: '\bbreakpoint\(\)'
language: pygrep
2. 디버거 안에서 무한 루프
pdb 안에서 c(continue)했는데 다시 같은 중단점에 걸리는 무한 → cl (모든 중단점 제거).
3. async 함수 디버깅
async def main():
breakpoint() # OK, 동작함
await long()
이벤트 루프가 정지하지만 그 안에서 양보 동작은 불가능. asyncio 전용 디버그 모드:
python -X dev script.py # asyncio dev mode 등
4. multiprocessing 디버깅
자식 프로세스는 stdin이 닫혀 pdb 입력 불가. 대안: pdb.set_trace(sys.stdin) 우회, 또는 디버그 시 process pool 비활성화.
💬 댓글