아래는 「파이썬 코딩의 기술 (Effective Python)」 2판의 아이템 75 "디버깅 출력에는 repr 문자열을 사용하라" 내용을 초보자도 쉽게 이해할 수 있도록 개념 → 코드 분석 → logging과의 차이 → 정리 순으로 꼼꼼하게 설명한 정리입니다.
디버깅 시 print() 대신 repr()을 활용하면 유용하다.
이유:
repr()
은 객체를 개발자 친화적으로 표현str()
보다 더 많은 정보를 제공eval(repr(obj))
로 원본 객체를 복원할 수 있도록 설계되는 경우가 많다또한, 클래스에 __repr__
을 구현하면, 객체의 디버깅 출력이 훨씬 가독성 있게 바뀐다.
함수 | 목적 | 출력 특징 |
---|---|---|
str(obj) | 사용자 친화적, 읽기 쉽게 | 사람이 보기 좋은 문자열 |
repr(obj) | 개발자 친화적, 디버깅용 | 객체를 다시 만들 수 있는 표현을 목표 |
print(obj) | 내부적으로 str(obj) 호출 | 기본은 사용자 친화적 출력 |
print('foo 뭐시기')
my_value = 'foo 뭐시기'
print(str(my_value)) # foo 뭐시기
print('%s' % my_value) # foo 뭐시기
print(f'{my_value}') # foo 뭐시기
print(format(my_value)) # foo 뭐시기
print(my_value.__str__()) # foo 뭐시기
a = '\x07'
print(repr(a)) # '\x07'
b = eval(repr(a))
assert a == b
repr()
결과를 eval()
하면 원본 객체 복원 가능(가능하도록 설계된 경우).int_value = 5
str_value = '5'
print(f'{int_value!r} != {str_value!r}') # 5 != '5'
!r
사용 → f-string에서도 repr 출력 강제.class OpaqueClass:
def __init__(self, x, y):
self.x = x
self.y = y
obj = OpaqueClass(1, 'foo')
print(obj)
# <__main__.OpaqueClass object at 0x7f3e2c9d5d60>
class BetterClass:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'BetterClass({self.x!r}, {self.y!r})'
obj = BetterClass(2, '뭐시기')
print(obj)
# BetterClass(2, '뭐시기')
__repr__
을 정의하면 디버깅 출력이 더 명확해짐.obj = OpaqueClass(4, 'baz')
print(obj.__dict__)
# {'x': 4, 'y': 'baz'}
__dict__
로 내부 상태 확인 가능하지만, 매번 수동으로 보기 불편.많은 초보자가 "디버깅에는 logging을 쓰면 되지 않나?" 라고 생각합니다.
하지만 아이템 75에서 강조하는 부분은 ‘디버깅 출력의 형식’입니다.
구분 | logging | repr |
---|---|---|
목적 | 로그 기록 (파일, 콘솔 등) | 객체를 개발자 친화적으로 출력 |
출력 포맷 | 사용자가 지정한 메시지 형식 | 객체의 상태를 자동으로 자세히 표시 |
사용 난이도 | logging 설정 필요 (레벨, 핸들러 등) | print(repr(obj)) 즉시 사용 가능 |
디버깅 정보 | 기본적으로 str() 사용 → 상세 정보 부족 | 이스케이프, 타입, 내부 표현까지 표시 |
__repr__
구현 시 디버깅 출력이 logging보다 직관적📝 결론: logging은 장기 로그 관리용, repr은 디버깅 순간에 강력.
print(obj)
대신 print(repr(obj))
사용{obj!r}
사용 → repr 출력 강제__repr__
을 구현하면 print만으로도 강력한 디버깅 가능"디버깅할 때는 str이 아닌 repr을 사용하라.
객체의 내부 상태를 더 잘 파악할 수 있고, 클래스에__repr__
을 구현하면 print만으로도 훌륭한 디버깅이 된다."