소멸자 메서드 __del__()이란?
__del__() 메서드는 파이썬에서 소멸자(destructor)라고 불리는 특수 메서드입니다. 이 메서드는 객체가 가비지 컬렉션(garbage collection)될 때 호출되며, 객체에 대한 모든 참조가 삭제된 이후에 실행됩니다.
class MyClass:
def __init__(self, name):
self.name = name
def __del__(self):
print(f'{self.name} 객체가 소멸되었습니다.')
obj = MyClass('테스트')
del obj # 모든 참조가 사라지면서 __del__ 호출기본적인 호출 시점
간단한 경우라면 del x처럼 변수를 삭제한 직후, 또는 x가 지역 변수라면 함수가 종료된 직후에 호출될 수 있습니다. 특히 순환 참조(circular reference)가 없다면, 표준 파이썬 구현체인 CPython은 즉시 가비지 컬렉션을 수행합니다.
실행 시점은 보장되지 않는다
파이썬 가비지 컬렉션에 대해 유일하게 보장되는 것은 "모든 참조가 삭제된 후에 실행된다"는 점뿐입니다. 따라서 참조가 삭제되자마자 곧바로 실행된다는 보장은 없으며, 심지어 아예 실행되지 않을 가능성도 있습니다.
더욱이 변수는 여러 가지 이유로 오랫동안 생명 주기를 유지할 수 있습니다. 예를 들어 다음과 같은 상황들이 대표적입니다.
- 전파 중인 예외(propagating exception): 예외 처리 과정에서 변수의 참조 카운트가 0보다 큰 상태로 유지될 수 있습니다.
- 모듈 인트로스펙션(module introspection): 디버깅 도구나 프레임워크가 변수를 계속 참조할 수 있습니다.
- 순환 참조: 변수가 순환 참조 구조의 일부가 되면 해제가 지연됩니다. CPython은 가비지 컬렉션이 활성화된 경우 대부분의 순환 참조를 끊어내지만, 전부는 아니며 그마저도 주기적으로만 수행합니다.
__del__()의 유효한 사용 사례
그럼에도 불구하고 __del__()에는 합법적인 활용 사례가 존재합니다. 예를 들어, 객체 X가 Y를 참조하고 있으면서 동시에 Y에 대한 참조 복사본을 전역 캐시에 보관하고 있다고 가정해 봅시다(cache['X -> Y'] = Y). 이런 경우 X.__del__이 해당 캐시 항목까지 함께 정리해주는 것이 바람직합니다.
또한 소멸자가 반드시 필요한 리소스 정리(clean-up) 작업을 수행한다는 것을 확실히 알고 있다면, x.__del__()처럼 메서드를 직접 호출하는 방식도 하나의 선택지가 될 수 있습니다.
정리
__del__()은 객체 소멸 시점에 자동으로 호출되지만, 그 실행 타이밍은 파이썬의 가비지 컬렉션 방식에 따라 달라지므로 신중하게 사용해야 합니다. 파일 핸들 닫기나 연결 해제 같은 필수적인 정리 작업은 with 문이나 명시적인 종료 메서드를 사용하는 것이 더 안전하며, __del__()은 보조적인 정리 용도로 활용하는 것이 좋습니다.