프로그램이 정상적으로 실행되든 오류가 발생하든 관계없이 반드시 수행해야 하는 작업이 필요한 상황이 자주 있습니다. 대표적인 예로 파일 닫기, 데이터베이스 연결 해제, 메모리 및 리소스 해제 등이 있으며, 이런 오류나 예외를 처리하기 위해 일반적으로 try와 except 블록을 사용합니다.
Python의 try 문에는 예외 발생 여부와 관계없이 어떤 경우에도 실행되어야 하는 '정리 작업(clean-up actions)'을 정의할 수 있는 매우 유용한 선택적 절인 finally가 제공됩니다. 먼저 간단한 예제를 살펴보겠습니다.
>>> try:
raise SyntaxError
finally:
print("Learning Python!")
Learning Python!
Traceback (most recent call last):
File "<pyshell#11>", line 2, in <module>
raise SyntaxError
File "<string>", line None
SyntaxError: <no detail available>
위 코드에서 확인할 수 있듯이 finally 절은 어떤 경우에도 항상 실행되지만, else 절은 예외가 발생하지 않았을 때만 실행된다는 점이 중요한 차이입니다.
예제 1 — 정상적으로 파일에 쓰기가 성공한 경우
아래 예제는 모든 조건이 정상이고, 파일에 쓰는 과정에서 예외가 전혀 발생하지 않는 경우입니다.
file = open('finally.txt', 'w')
try:
file.write("Testing1 2 3.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")위 프로그램을 실행하면 다음과 같은 결과를 얻습니다.
Writing to file.
Write successful.
File closed.
쓰기 작업이 성공했으므로 except 블록은 건너뛰고 else 블록이 실행된 후, 마지막으로 finally 블록에서 파일이 안전하게 닫힙니다.
예제 2 — 읽기 전용 파일에 쓰기를 시도해 예외 발생시키기
이번에는 파일을 읽기 전용 모드('r')로 연 뒤 쓰기를 시도함으로써 의도적으로 예외를 발생시켜 보겠습니다.
file = open('finally.txt', 'r')
try:
file.write("Testing1 2 3.")
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")위 프로그램은 다음과 비슷한 출력을 생성합니다.
Could not write to file.
File closed.
예외가 발생했기 때문에 else 블록은 실행되지 않았지만, finally 블록은 여전히 실행되어 파일이 정상적으로 닫혔습니다.
처리되지 않은 오류가 있을 때의 finally 동작
그렇다면 오류가 발생했는데 이를 처리할 except 절이 아예 없는 경우에는 어떻게 될까요? 이 경우 정리 작업(finally 블록)이 먼저 실행된 후, 인터프리터가 오류를 발생시킵니다. 아래 예제로 이 개념을 이해해 보겠습니다.
file = open('finally.txt', 'r')
try:
file.write(4)
print("Writing to file.")
except IOError:
print("Could not write to file.")
else:
print("Write successful.")
finally:
file.close()
print("File closed.")출력
File closed.
Traceback (most recent call last):
File "C:/Python/Python361/finally_try_except1.py", line 4, in <module>
file.write(4)
TypeError: write() argument must be str, not int
여기서 주목할 점은 문자열이 아닌 정수를 쓰려고 시도해 발생한 TypeError는 IOError를 처리하는 except 절에서 잡을 수 없었다는 것입니다. 하지만 그럼에도 불구하고 finally 블록의 "File closed."가 트레이스백보다 먼저 출력된 것을 확인할 수 있습니다.
결국 위의 모든 예제에서 알 수 있듯이, finally 절은 예외가 발생하든 발생하지 않든, 심지어 예외가 처리되지 않아 프로그램이 종료되는 상황에서도 항상 실행됩니다. 이러한 특성 덕분에 파일 핸들이나 네트워크 연결 같은 시스템 리소스를 안전하게 해제할 수 있으며, 예상치 못한 오류로 인한 리소스 누수(resource leak)를 효과적으로 방지할 수 있습니다.