파이썬 atexit 모듈을 빠르게 사용하기 위한 치트시트입니다. 종료 콜백 등록, 리소스 정리, 임시 파일 삭제 등 프로그램 종료 시 실행할 작업을 최소 예제로 정리합니다.
atexit 모듈은 프로그램 정상 종료 시 실행할 함수를 등록합니다. 리소스 정리, 임시 파일 삭제, 로그 기록 등 종료 작업에 유용합니다.
언제 이 치트시트를 보나?
프로그램 종료 시 리소스 정리가 필요할 때
임시 파일 삭제를 보장하고 싶을 때
종료 로그를 남기고 싶을 때
핵심 함수
1
2
3
4
importatexitatexit.register(func,*args,**kwargs)# 종료 콜백 등록atexit.unregister(func)# 콜백 제거
최소 예제
1. 기본 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
importatexitdefcleanup():print("Cleanup: Closing resources...")defgoodbye(name):print(f"Goodbye, {name}!")# 종료 콜백 등록atexit.register(cleanup)atexit.register(goodbye,"User")print("Program running...")# 프로그램 종료 시:# Goodbye, User!# Cleanup: Closing resources...# (LIFO 순서로 실행)
importatexitimportostemp_files=[]defcreate_temp_file(name):temp_files.append(name)withopen(name,'w')asf:f.write("temp data")returnnamedefcleanup_temp_files():forfintemp_files:ifos.path.exists(f):os.remove(f)print(f"Removed: {f}")atexit.register(cleanup_temp_files)# 임시 파일 생성create_temp_file('temp1.txt')create_temp_file('temp2.txt')# 종료 시 자동 삭제
4. 데이터베이스 연결 종료
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
importatexitclassDatabase:def__init__(self,name):self.name=nameself.connected=Trueprint(f"Connected to {name}")# 종료 시 자동 disconnectatexit.register(self.disconnect)defdisconnect(self):ifself.connected:print(f"Disconnecting from {self.name}")self.connected=Falsedb=Database("mydb")print("Using database...")# 종료 시 자동으로 disconnect 호출
5. 콜백 제거
1
2
3
4
5
6
7
8
9
10
importatexitdefmy_cleanup():print("This won't run")atexit.register(my_cleanup)# 조건에 따라 제거ifsome_condition:atexit.unregister(my_cleanup)
6. 종료 로그 기록
1
2
3
4
5
6
7
8
9
importatexitfromdatetimeimportdatetimedeflog_shutdown():timestamp=datetime.now().isoformat()withopen('shutdown.log','a')asf:f.write(f"Program terminated at {timestamp}\n")atexit.register(log_shutdown)
7. 여러 핸들러 순서
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
importatexitdeffirst():print("First (registered first, runs last)")defsecond():print("Second")defthird():print("Third (registered last, runs first)")atexit.register(first)atexit.register(second)atexit.register(third)# 종료 시 출력:# Third (registered last, runs first)# Second# First (registered first, runs last)
importatexitclassService:instances=[]def__init__(self,name):self.name=nameService.instances.append(self)defcleanup(self):print(f"Cleaning up {self.name}")@classmethoddefcleanup_all(cls):forinstanceincls.instances:instance.cleanup()atexit.register(Service.cleanup_all)s1=Service("Service1")s2=Service("Service2")
9. 컨텍스트 매니저와 함께
1
2
3
4
5
6
7
8
9
10
11
12
13
importatexitfromcontextlibimportcontextmanager@contextmanagerdefmanaged_resource(name):resource=acquire_resource(name)# 종료 시 정리 보장atexit.register(release_resource,resource)try:yieldresourcefinally:release_resource(resource)atexit.unregister(release_resource)
importatexitimportosdefcleanup():print("This may not run")atexit.register(cleanup)# 실행되지 않는 경우:# 1. os._exit() 호출 시os._exit(1)# atexit 핸들러 무시# 2. SIGKILL로 종료 시 (kill -9)# 3. 치명적 에러 (segfault 등)# 실행되는 경우:# - sys.exit()# - 정상 종료# - 처리되지 않은 예외
자주 하는 실수
1. 람다 사용 시 클로저 문제
1
2
3
4
5
6
7
8
9
10
11
12
importatexitfiles=[]# 잘못: 람다는 나중에 평가됨fornamein['a.txt','b.txt']:atexit.register(lambda:print(f"Cleanup {name}"))# 모두 "Cleanup b.txt" 출력# 올바름: 기본값으로 캡처fornamein['a.txt','b.txt']:atexit.register(lambdan=name:print(f"Cleanup {n}"))
2. 핸들러에서 예외
1
2
3
4
5
6
7
8
9
10
11
12
13
importatexitdefbad_handler():raiseException("Error in cleanup")defgood_handler():try:risky_operation()exceptExceptionase:print(f"Cleanup error: {e}")atexit.register(good_handler)atexit.register(bad_handler)# 예외가 출력되고 다음 핸들러 계속
atexit vs del vs finally
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
importatexit# atexit: 프로그램 종료 시 (권장)atexit.register(cleanup)# __del__: 객체 소멸 시 (신뢰하기 어려움)classMyClass:def__del__(self):pass# 호출 시점 불확실# finally: 블록 종료 시try:work()finally:cleanup()# 항상 실행# 컨텍스트 매니저: 가장 명확withresourceasr:work()# 종료 시 __exit__ 호출