Python을 처음 배우거나, 코드를 작성하다가 어디서 잘못됐는지 몰라 막막했던 경험이 있으신가요?
이 글에서는 파이썬 초보자와 중급자를 위한 디버깅 기초, assert 문 사용법, 테스트 케이스 작성법을 소개합니다. 또한 파이썬 코딩에서 흔히 마주치는 구문 에러, 실행 시 에러, 논리 에러의 차이점도 예제와 함께 설명합니다.
Python으로 안정적인 코드를 작성하고 싶은 분이라면, 지금부터 소개할 사양 분석부터 테스트, 디버깅, 그리고 PEP8 기반 코딩 스타일까지 꼭 참고해보세요. 이해하기 쉬운 예제와 함께 따라할 수 있도록 구성했습니다.
사양・테스트・디버그에 대하여
프로그래밍을 할 때, 실현하고자 하는 내용을 사양(仕様, Specification) 이라고 부릅니다.
작성한 프로그램이 사양에 부합하는지를 실제로 실행하여 검사하는 작업을 테스트(Test) 라고 합니다. 이때 테스트 대상에 주어지는 입력과 기대되는 출력을 한 쌍으로 만든 것을 테스트 케이스(Test Case) 라고 부릅니다.
작성된 프로그램이 사양에 부합하는지 여부는 일반적으로 자명하지 않습니다. 테스트를 통해 사양에 위배된 프로그램의 동작이 드러나기도 하며, 이와 같은 사양 위반의 원인을 버그(Bug) 라고 부릅니다. 이 버그를 찾아 제거하는 작업을 디버그(Debug) 라고 합니다.
프로그래밍은 일반적으로 아래와 같은 흐름을 반복합니다:
- 사양을 분석한다
- 프로그램을 작성한다
- 테스트를 한다
- 디버그를 한다
assert 문
테스트와 디버그에 유용한 것이 바로 assert 문입니다.assert
뒤에 오는 조건식이 참이어야 한다는 것을 선언하는 문장입니다.
만약 그 조건이 거짓일 경우, AssertionError
가 발생하며 프로그램이 중단됩니다.
예시로, 주어진 인수를 제곱하는 square
함수에 대해 살펴보겠습니다.
def square(x):
return x*x
x = -2
assert square(x) >= 0
위의 assert
문은 square(x) >= 0
이 사양이라는 것을 선언합니다.square
함수가 제대로 제곱을 수행하고 있다면, 이 조건은 참이므로 문제가 없습니다.
하지만 다음과 같이 버그가 있는 경우는 다릅니다.
def square(x):
return x+x # 버그가 있는 코드
x = -2
assert square(x) >= 0
AssertionError:
이처럼 assert
문은 해당 지점에서 충족되어야 할 전제 조건을 명시하는 데 사용되며,
중단되었다면 그 부분에 버그가 있을 가능성이 높습니다.
또한 assert
문은 테스트 케이스의 검증에도 사용될 수 있습니다.
def square(x):
return x*x
assert square(2) == 4
assert square(-2) == 4
assert square(0) == 0
이 테스트가 모두 통과하더라도 square
함수가 완벽히 옳다고 단정할 수는 없지만,
사양과 부합할 가능성이 높아 보인다는 근거가 됩니다.
에러의 종류
잘못된 프로그램은 다양한 종류의 에러(Error) 를 발생시킵니다.
에러는 크게 아래의 세 가지로 나뉩니다:
- 구문 에러 (Syntax Error)
- 실행 시 에러 (Runtime Error)
- 논리 에러 (Logic Error)
구문 에러 (Syntax Error)
Python 문법에 맞지 않는 경우 발생합니다.
예시:
print('This is the error) # 따옴표 닫기 안함
def f() # 콜론 생략
return 1
def f():
return 1 # 들여쓰기 없음
1 + 1 # 전각 스페이스 사용
이러한 에러가 발생하면 SyntaxError
, IndentationError
등의 메시지가 출력되며,
어디서 문제가 생겼는지 Python이 알려줍니다.
구문 에러는 프로그램 실행 도중 생기는 것이 아니라,
실행을 시도할 때 Python이 코드를 해석하지 못해서 발생하는 것입니다.
실행 시 에러 (Runtime Error)
프로그램 실행 중에 발생하는 에러입니다.
주로 프로그램이 비정상적으로 중단되는 경우입니다.
대표적인 사례:
undefined_variable # 존재하지 않는 변수
x = 1
def f():
x = x # 로컬 변수 참조 오류
f()
1 / 0 # 0으로 나누기
{'a': 1}['b'] # 등록되지 않은 키 참조
open('non-existent.txt', 'r') # 없는 파일 열기
이처럼 NameError
, UnboundLocalError
, ZeroDivisionError
, KeyError
, FileNotFoundError
등이 발생하며,
에러 메시지를 통해 원인을 파악할 수 있습니다.
논리 에러 (Logic Error)
프로그램은 실행되지만 의도한 대로 동작하지 않는 경우입니다.
이것은 코드 자체에 문제가 있는 것이 아니라 프로그래머의 사고 오류로 인해 발생합니다.
대부분의 버그는 이 논리 에러에 해당합니다.assert
문은 이런 논리적 오류를 AssertionError
로 변환하여 잡아내는 역할도 합니다.
디버깅 예시
다음은 중간값(中央値)을 구하는 함수 median(x, y, z)
의 예입니다.
단, x
, y
, z
는 서로 다른 값이라고 가정합니다.
def median(x, y, z):
if x > y:
x = y
y = x
if z < x:
return x
if z < y:
return z
return y
assert median(3, 1, 2) == 2
위 함수는 에러 없이 실행되지만, 잘못된 값을 반환합니다.
디버깅을 위해 중간 상태를 print()
문으로 출력해보겠습니다.
def median(x, y, z):
print(x, y, z)
if x > y:
x = y
y = x
print(x, y, z)
if z < x:
return x
if z < y:
return z
return y
출력 결과를 보면 x
와 y
의 값이 잘못 바뀌었다는 것이 확인됩니다.
올바르게 바꾸려면 임시 변수를 사용해 아래처럼 수정해야 합니다.
def median(x, y, z):
print(x, y, z)
if x > y:
w = x
x = y
y = w
print(x, y, z)
if z < x:
return x
if z < y:
return z
return y
정상 작동이 확인되면, 디버깅용 print
문은 제거합니다.
def median(x, y, z):
if x > y:
w = x
x = y
y = w
if z < x:
return x
if z < y:
return z
return y
assert median(3, 1, 2) == 2
✍️ 코딩 스타일의 중요성
사실 버그를 고치는 것보다, 애초에 버그가 생기지 않도록 예방하는 것이 훨씬 중요합니다.
Python에서는 PEP8 이라는 코딩 스타일 가이드라인이 존재합니다.
가독성을 높이고 실수를 줄이기 위해, 다음과 같은 규칙들이 있습니다:
- 들여쓰기는 공백 4칸
=
,+
,==
등의 연산자는 양쪽에 공백 1칸- 함수명 뒤 괄호
()
앞에는 공백 금지 l
,I
,O
와 같은 혼동되는 변수명은 사용하지 않기== True
보다if condition:
식으로 쓰기
또한,
- 의미 없는 숫자(매직넘버) 는 변수명으로 치환하기
- 불필요한 코드 제거
- 하나의 함수는 하나의 역할만 하도록 구성
이러한 습관은 버그를 줄이고, 향후 유지보수도 훨씬 쉽게 만들어줍니다.
'튜토리얼' 카테고리의 다른 글
Colaboratory(Colab)로 배우는 Python 문자열 완전 정복 – 2부: 검색, 치환, 메서드 정리편 (0) | 2025.06.29 |
---|---|
Colaboratory(Colab)로 배우는 Python 문자열 완전 정복 – 1부: 문자열, 타입, 인덱싱, 슬라이싱 (0) | 2025.06.29 |
Colaboratory(Colab)로 배우는 조건 분기와 논리/비교 연산의 기본 개념 (2) | 2025.06.26 |
Colaboratory(Colab)로 배우는 파이썬 수치 연산: 기초부터 실전까지 (1) | 2025.06.26 |
Colaboratory(Colab) 시작하기: 파이썬 노트 입문 가이드 (0) | 2025.06.26 |