4.1. print 디버깅

처음에는 IDE 디버거보다 먼저, print()를 이용해 실행 흐름과 현재 상태를 확인하는 습관을 익히는 데 초점을 맞춥니다.
1. print 디버깅이란?
print 디버깅은 단순히 값을 출력하는 기능이 아니라, 프로그램이 어디까지 실행되었는지, 현재 변수값이 무엇인지, 조건문이 어느 방향으로 흘렀는지를 확인하는 가장 기본적인 디버깅 방법입니다.
IDE 디버거를 사용하기 전에도 충분히 학습할 수 있고, 초보자에게는 실행 흐름을 눈으로 확인하는 첫 훈련으로 매우 중요합니다.
핵심 흐름
- 어디까지 실행되었는지 확인하기
- 현재 값이 무엇인지 확인하기
- 조건문이 어느 쪽으로 갔는지 확인하기
- 반복문에서 값이 어떻게 바뀌는지 확인하기
- 함수에 어떤 값이 들어가고 어떤 값이 나오는지 확인하기
- 오류가 발생하기 직전 위치를 좁혀 가기
2. 학습 목표
- print()를 이용해 실행 흐름을 확인할 수 있습니다.
- 변수값과 자료형을 직접 출력해 현재 상태를 점검할 수 있습니다.
- 조건문, 반복문, 함수 내부의 동작을 단계적으로 추적할 수 있습니다.
- 오류가 발생한 위치를 print 출력 흐름으로 좁혀 갈 수 있습니다.
- 나중에 IDE 디버깅으로 넘어가기 전, 디버깅의 기본 사고방식을 익힐 수 있습니다.
3. 단계별 print 디버깅 실습
3.1 실행 흐름 확인하기
가장 먼저 익혀야 하는 것은 프로그램이 어디까지 실행되었는지 확인하는 print 입니다.
기본 코드
def add(a, b):
result = a + b
return result
x = 10
y = 5
answer = add(x, y)
print(answer)
print 추가 버전
def add(a, b):
print("1. add 함수 시작")
result = a + b
print("2. 계산 완료")
return result
print("3. 프로그램 시작")
x = 10
y = 5
answer = add(x, y)
print("4. 함수 호출 완료")
print(answer)
학습 포인트
- 프로그램은 위에서 아래로 순서대로 실행됩니다.
- 함수 안과 함수 밖의 실행 흐름을 구분해서 볼 수 있습니다.
- “어디까지 실행되었는가”를 먼저 확인하는 습관이 중요합니다.
3.2 변수값 확인하기
다음 단계는 현재 값이 무엇인지 확인하는 print 입니다. 계산이 이상할 때는 계산식보다 먼저 변수값이 맞는지 확인해야 합니다.
기본 코드
def subtract(a, b):
result = a - b
return result
x = 10
y = 3
answer = subtract(x, y)
print(answer)
print 추가 버전
def subtract(a, b):
print("a =", a)
print("b =", b)
result = a - b
print("result =", result)
return result
x = 10
y = 3
print("x =", x)
print("y =", y)
answer = subtract(x, y)
print("최종 결과 =", answer)
학습 포인트
- 함수 안의 매개변수와 바깥 변수는 이름이 달라도 실제 값이 연결됩니다.
- 계산 전 값과 계산 후 값을 구분해서 보는 것이 좋습니다.
- 틀린 결과가 나오면 먼저 입력값부터 확인하는 습관이 중요합니다.
3.3 오류가 발생하는 위치 좁혀 가기
이번에는 실제 오류가 발생하는 예시입니다. 핵심은 오류 메시지와 함께, 어디까지 정상 실행되었는지 print로 찾는 것 입니다.
기본 코드
def divide(a, b):
result = a / b
return result
x = 10
y = 0
answer = divide(x, y)
print(answer)
print 추가 버전
def divide(a, b):
print("1. divide 함수 시작")
print("a =", a)
print("b =", b)
print("2. 나눗셈 직전")
result = a / b
print("3. 나눗셈 완료")
return result
print("4. 프로그램 시작")
x = 10
y = 0
print("5. 함수 호출 직전")
answer = divide(x, y)
print("6. 함수 호출 완료")
print(answer)
예상 출력 흐름
4. 프로그램 시작
5. 함수 호출 직전
1. divide 함수 시작
a = 10
b = 0
2. 나눗셈 직전
학습 포인트
"2. 나눗셈 직전"까지는 정상 실행되었습니다."3. 나눗셈 완료"는 출력되지 않았습니다.- 즉, 오류는
result = a / b줄 근처에서 발생했다고 추적할 수 있습니다.
3.4 조건문 분기 확인하기
조건문 디버깅에서는 어느 블록으로 들어갔는지 뿐 아니라, 조건식 결과 자체를 함께 출력하는 것이 좋습니다.
기본 코드
score = 75
if score >= 80:
print("합격")
else:
print("불합격")
print 추가 버전
score = 75
print("score =", score)
print("score >= 80 결과 =", score >= 80)
if score >= 80:
print("if 블록으로 들어왔습니다.")
print("합격")
else:
print("else 블록으로 들어왔습니다.")
print("불합격")
학습 포인트
- 조건식은 참인지 거짓인지 직접 출력할 수 있습니다.
- “왜 else로 갔는가?”를 추측이 아니라 값으로 확인할 수 있습니다.
- 조건문 디버깅에서는 조건식 결과 출력이 매우 중요합니다.
3.5 반복문 안의 값 변화 추적하기
반복문은 같은 줄이 여러 번 실행되기 때문에 현재 몇 번째 반복인지, 현재 값이 무엇인지를 같이 출력해야 합니다.
기본 코드
numbers = [10, 20, 30]
total = 0
for n in numbers:
total = total + n
print(total)
print 추가 버전
numbers = [10, 20, 30]
total = 0
print("반복문 시작 전 total =", total)
for index, n in enumerate(numbers):
print("------")
print("현재 반복 index =", index)
print("현재 n =", n)
print("더하기 전 total =", total)
total = total + n
print("더한 후 total =", total)
print("반복문 종료 후 total =", total)
학습 포인트
- 반복문에서는
index를 함께 출력하면 흐름을 이해하기 쉽습니다. - 변경 전 값과 변경 후 값을 나눠서 보는 것이 중요합니다.
- 반복문 오류는 한 번에 보지 말고, 한 바퀴씩 추적해야 합니다.
3.6 반복문 속 논리 오류 찾기
이번에는 문법 오류가 아니라, 결과는 나오지만 논리가 잘못된 코드를 찾는 연습입니다.
기본 코드
numbers = [10, 20, 30]
total = 0
for n in numbers:
total = n
print(total)
이 코드는 누적합이 아니라 마지막 값인 30만 남게 됩니다.
print 추가 버전
numbers = [10, 20, 30]
total = 0
for index, n in enumerate(numbers):
print("반복 index =", index)
print("현재 n =", n)
print("대입 전 total =", total)
total = n
print("대입 후 total =", total)
print("최종 total =", total)
학습 포인트
total = total + n이 아니라total = n이 되어 누적이 되지 않습니다.- print를 통해 누적이 아니라 덮어쓰기가 일어나고 있음을 확인할 수 있습니다.
- 이 단계는 논리 오류를 눈으로 찾는 훈련에 매우 좋습니다.
3.7 함수에 들어가는 값과 나오는 값 추적하기
값이 함수 안으로 들어가고 다시 바깥으로 나오는 흐름을 추적하면, 디버깅이 훨씬 쉬워집니다.
기본 코드
def multiply(a, b):
result = a * b
return result
def calculate():
x = 4
y = 5
answer = multiply(x, y)
print(answer)
calculate()
print 추가 버전
def multiply(a, b):
print("[multiply] 시작")
print("[multiply] a =", a)
print("[multiply] b =", b)
result = a * b
print("[multiply] result =", result)
return result
def calculate():
print("[calculate] 시작")
x = 4
y = 5
print("[calculate] x =", x)
print("[calculate] y =", y)
answer = multiply(x, y)
print("[calculate] answer =", answer)
calculate()
학습 포인트
- 함수 시작점과 종료점에 print를 넣으면 흐름이 잘 보입니다.
- 함수 안쪽과 바깥쪽 출력을 구분하기 위해
[함수이름]형태를 붙이면 좋습니다. - 어떤 값이 들어가고 어떤 값이 반환되는지 추적할 수 있습니다.
3.8 값뿐 아니라 자료형도 확인하기
초보자에게 자주 발생하는 문제 중 하나는 값은 숫자처럼 보이지만 실제로는 문자열인 경우입니다.
기본 코드
x = input("첫 번째 숫자: ")
y = input("두 번째 숫자: ")
result = x + y
print(result)
예를 들어 10, 20을 입력하면 30이 아니라 1020이 출력됩니다.
print 추가 버전
x = input("첫 번째 숫자: ")
y = input("두 번째 숫자: ")
print("x =", x)
print("y =", y)
print("x의 자료형 =", type(x))
print("y의 자료형 =", type(y))
result = x + y
print("result =", result)
학습 포인트
- 값뿐 아니라
type()으로 자료형도 확인할 수 있습니다. - 문자열끼리 더하면 숫자 덧셈이 아니라 문자열 연결이 됩니다.
- print 디버깅은 자료형 문제를 찾는 데도 유용합니다.
3.9 오류가 나는 입력 직접 찾기
마지막 단계에서는 학습자가 스스로 어떤 입력에서 오류가 발생하는지 찾도록 구성하면 좋습니다.
기본 코드
def safe_divide(a, b):
return a / b
x = int(input("첫 번째 숫자: "))
y = int(input("두 번째 숫자: "))
result = safe_divide(x, y)
print(result)
힌트용 print 버전
def safe_divide(a, b):
print("[safe_divide] a =", a)
print("[safe_divide] b =", b)
print("[safe_divide] 나눗셈 직전")
return a / b
x = int(input("첫 번째 숫자: "))
y = int(input("두 번째 숫자: "))
print("[main] x =", x)
print("[main] y =", y)
result = safe_divide(x, y)
print("[main] result =", result)
학생 확인 질문
- 어떤 입력에서 오류가 발생하는가?
- 오류가 나기 직전까지 어떤 값이 출력되는가?
- 함수 안에 print를 넣으면 어디까지 실행되는가?
b값이 무엇일 때 위험한가?
4. print 디버깅 기본 규칙
학습 초반에는 아래 6가지 형태만 익혀도 충분합니다.
4.1 위치 확인용 print
print("여기까지 실행됨")
4.2 값 확인용 print
print("x =", x)
4.3 조건 확인용 print
print("x > 10 결과 =", x > 10)
4.4 반복문 추적용 print
print("index =", index, "value =", value)
5. 마무리 정리
print 디버깅은 단순히 값을 출력하는 기능이 아니라,
프로그램의 실행 흐름과 현재 상태를 확인하는 가장 기본적인 디버깅 방법입니다.
처음에는 “어디까지 실행되었는가”를 확인하고,
그다음에는 “현재 값이 무엇인가”, “어느 조건으로 들어갔는가”, “반복문에서 값이 어떻게 바뀌는가”를 차례대로 확인하는 훈련이 중요합니다.
이후 IDE 디버깅은 이 과정을 더 편하게 해 주는 도구라고 이해하면 됩니다.