파이썬 초보자가 알아야 할 7가지 디버깅 기법

"왜 이 코드가 작동하지 않지?"라는 질문으로 수 시간을 보낸 적이 있다면, 환영합니다. 초보자라면 오류 메시지, 복잡한 스택 트레이스, 이상한 출력 결과에 좌절감을 느낄 수 있습니다. 디버깅은 이러한 버그를 찾고 수정하는 기술이며, 실제로 가장 많은 학습이 이루어지는 단계입니다. 오류는 피할 수 없지만, 디버깅 기술을 향상시키면 많은 시간과 좌절감을 줄일 수 있습니다. 이 글에서는 초보자가 알아두면 유용한 7가지 실용적인 디버깅 기법을 소개합니다.
1. Print 문과 로깅
초보자들이 가장 먼저 시도하는 것은 print()
문을 코드에 넣어 무슨 일이 일어나고 있는지 확인하는 것입니다. 변수 값이나 루프 내부의 "체크포인트" 메시지를 출력하면 예상치 못한 값을 빠르게 찾을 수 있습니다. 초보자들이 자주 저지르는 실수는 이러한 print문을 업데이트하거나 제거하지 않는 것, 또는 충분한 컨텍스트를 제공하지 않는 것입니다. 예를 들어 라벨 없이 print(x)
만 하면 혼란스러울 수 있습니다. print(f"x is {x}")
처럼 컨텍스트를 추가하여 더 명확하게 만들 수 있습니다. 전문적인 코드에서는 일반적으로 로깅 모듈을 사용합니다:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("something happened: %s", var)
이렇게 하면 타임스탬프와 레벨을 얻을 수 있고, 로깅을 켜거나 끄거나 파일로 리디렉션할 수 있습니다. 간단히 말해, 빠른 확인을 위해 print()
를 사용하면 초보자 버그의 80%를 해결할 수 있지만, 로깅 방법도 배우는 것이 좋습니다. 잘 배치된 print문이나 로그는 프로그램의 흐름을 시각화하는 데 도움이 됩니다.
2. 오류 메시지(스택 트레이스) 읽기
파이썬이 충돌할 때, 스택 트레이스라고 하는 오류로 이어지는 호출 추적을 출력합니다. 당황하지 마세요! 자세히 읽어보세요. 마지막 줄이 가장 중요합니다: 오류 유형과 메시지를 보여줍니다. 초보자들은 종종 트레이스의 상단을 무시하지만, 아래에서 위로 읽어야 합니다. 오류 유형(예: ValueError, IndexError)과 메시지를 확인하세요 - 보통 무엇이 잘못되었는지 정확히 알려줍니다(예: "list index out of range" 또는 "NameError: name 'foo' is not defined"). 그런 다음 위에 있는 파일 이름과 줄 번호를 보고 코드의 어디에서 오류가 발생했는지 확인하세요. 정확한 오류 메시지를 검색하면 같은 문제를 겪은 다른 사람들의 답변을 찾을 수 있습니다.
3. Assertions(유효성 검사) 사용하기
때로는 오류가 오타가 아닌 예상치 못한 데이터 위반으로 인해 발생합니다. 파이썬의 assert
문은 이러한 버그를 조기에 발견할 수 있습니다. assert
는 "여기서 이것은 반드시 참이어야 한다"라고 말하는 것과 같습니다 - 그렇지 않으면 파이썬은 AssertionError
를 발생시킵니다. 예를 들면:
value = get_value()
assert value >= 0, "value should never be negative"
이렇게 하면 value
가 잘못되면 즉시 알려줍니다. 초보자들은 종종 입력을 확인하지 않아 이상한 오류가 발생합니다. 함수에 assert를 사용하여 주요 가정(예: 입력 범위, 비어 있지 않은 리스트, 올바른 유형)을 검증하세요. assert가 실패하면 트레이스는 어떤 가정이 깨졌는지 정확히 보여주어 버그를 쉽게 찾을 수 있습니다.
4. 변수 범위 이해하기(전역 vs. 지역)
버그는 종종 변수가 생각했던 것과 다를 때 발생합니다. 파이썬에서 함수 내부에서 정의된 변수는 명시적으로 global로 선언되지 않는 한 해당 함수에 국한됩니다. 예를 들어:
count = 0
def increment():
count += 1 # 이런! 이건 오류를 발생시킵니다
return count
increment()
이 코드를 실행하면 UnboundLocalError: local variable 'count' referenced before assignment
가 발생합니다. count
가 바깥에 정의되어 있더라도, count += 1
라인은 파이썬이 count를 지역 변수로 취급하게 만들고, 설정되기 전에 참조됩니다. 이를 해결하기 위해 함수 내에서 global count
를 선언하거나, 더 좋은 방법은 범위를 혼합하지 않는 것입니다. 더 명확한 예:
x = 5
def foo():
print(x) # 이것은 작동합니다(5 출력)
foo()
여기서 x는 함수에서 읽혀지고 파이썬은 전역 x를 찾습니다. 하지만 x에 할당하려고 하면:
x = 5
def foo():
x = x + 1 # 오류! 파이썬은 이제 x를 지역 변수로 간주합니다
print(x)
foo()
이는 실패합니다. 규칙은: 함수 내에서 이름에 할당하면 그것을 지역 변수로 만들기 때문에, 전역 변수를 의도했다면 파이썬은 혼란스러워합니다. 함수 내에서 변수 이름을 바꾸거나 global
을 사용하는 것이 해결책일 수 있습니다. 이를 알면 신비한 "변수가 정의되지 않음" 오류를 피할 수 있습니다.
5. 가변 기본 인자 함정 피하기
파이썬의 전형적인 함정 중 하나는 함수의 기본 인자, 특히 리스트나 딕셔너리와 같은 가변 객체를 사용할 때 발생합니다. 예를 들어:
def additem(item, mylist=[]):
my_list.append(item)
return my_list
print(add_item("apple")) # ['apple']
print(add_item("banana")) # ['apple', 'banana'] - 이런, 'apple'이 남아있습니다!
각 호출이 빈 리스트로 시작할 것으로 예상했을 수 있지만, 대신 리스트는 이전 호출을 "기억"합니다. 그 이유는 파이썬이 기본 인자를 함수가 정의될 때 한 번만 평가하고, 호출될 때마다 평가하지 않기 때문입니다. 그래서 같은 리스트가 재사용됩니다. 더 안전한 패턴은 None
을 사용한 후 내부에 새 리스트를 만드는 것입니다:
def additem(item, mylist=None):
if my_list is None:
my_list = []
my_list.append(item)
return my_list
이제 명시적 리스트 없이 각 호출은 새로운 리스트를 받습니다. 이 특이점을 알고 있으면 많은 혼란을 방지할 수 있습니다!
6. IDE 및 에디터 디버거
VS Code, PyCharm, Spyder와 같은 현대 코드 에디터에는 시각적 디버거가 내장되어 있습니다. 이를 통해 클릭 한 번으로 중단점을 설정하고 "디버그" 모드에서 코드를 실행할 수 있습니다. 실행이 중단점에 도달하면 IDE는 모든 지역 변수, 호출 스택을 보여주고 코드를 한 줄씩 또는 함수 내부로 단계별로 진행할 수 있게 해줍니다. 이는 종종 초보자에게 명령줄 pdb 프롬프트보다 더 쉽습니다. 예를 들어, 줄 옆의 여백을 클릭하여 거기에서 일시 중지할 수 있습니다. 그런 다음 변수 위에 마우스를 올려 값을 보거나 "변수" 창을 열 수 있습니다. PyCharm과 VS Code는 표현식을 감시하고 단계적으로 진행할 때 현재 줄을 강조 표시할 수도 있습니다. IDE 디버거를 사용하면 print 문으로 코드를 어지럽힐 필요가 없습니다. IDE 디버거를 배우는 데 시간을 투자하면 큰 도움이 됩니다.
7. 러버 덕(고무 오리) 기법과 다른 생각 기법들
마지막으로, 때로는 최고의 "디버거"는 당신 자신(또는 고무 오리)입니다. 이 오래된 트릭은 러버 덕 디버깅이라고 알려져 있으며, 다른 사람이나 심지어 무생물에게 코드를 한 줄씩 설명하는 것을 의미합니다. 코드가 무엇을 해야 하는지 말로 표현하면 종종 모순이나 실수가 드러납니다. 초보자들은 코드를 소리 내어 읽거나 종이에 단계별로 진행하면서 자신의 버그를 발견하는 경우가 많습니다. 간단한 용어로 로직을 설명해 보세요: 예를 들어 "먼저 이것을 확인한 다음, 저것을 업데이트합니다... 잠깐, 왜 두 번 하고 있지?" 갑자기 다른 것을 의도했다는 것을 깨달을 수 있습니다. 페어 프로그래밍이나 친구에게 들어달라고 요청하는 것도 도움이 됩니다. 때로는 문제를 소리 내어 표현하는 것만으로도 해결책을 찾을 수 있습니다. 이것은 명령이 있는 기술적 도구가 아니라 마음가짐입니다: 뒤로 물러서서, 심호흡하고, 코드를 통해 이성적으로 생각해보세요. 종종 천천히 각 단계를 명확히 할 때 버그가 튀어나옵니다.
마무리
이러한 각 기법은 다양한 종류의 버그를 노출시킬 수 있습니다. 실제로는 이들의 조합이 가장 효과적입니다: 오류 메시지를 읽는 것으로 시작하고, 예상과 다른 부분을 찾기 위해 print/로그 문이나 assertions를 추가하며, 복잡한 상태를 검사해야 할 때 대화형 디버거나 IDE를 사용하세요. 디버깅은 코딩의, 정상적인 부분이라는 것을 기억하세요 - 전문가들도 디버깅합니다! 여러분이 수정하는,, 모든 버그는 배움의 기회입니다.