Python atexit: จองคิวเก็บกวาดก่อนโปรเซสจบ
สกิลป์ต์สั้นๆ ที่เปิดไฟล์ชั่วคราวหรือล็อกพอร์ต มักลืมปิดของตอนจบครับ atexit.register ใส่ฟังก์ชันเข้าคิวให้ interpreter เรียกก่อนจบแบบปกติ ลำดับเป็น LIFO — ตัวที่ลงทะเบียนทีหลังถูกเรียกก่อน
WHY: cleanup ที่ไม่ต้องห่อ try/finally ทั้ง main
เหมาะกับปลั๊กอินหรือไลบรารีที่ไม่ได้ควบคุม main ของคนเรียก แต่ต้องคืนทรัพยากร เอกสารบอกชัดว่า handler จะไม่รันถ้าโปรเซสถูกฆ่าด้วยสัญญาณที่ไม่อนุญาตให้ cleanup หรือถ้าเรียก os._exit
import atexit
import unittest
class AtexitRegisterTests(unittest.TestCase):
def test_register_runs_lifo_and_unregister(self):
log = []
def first():
log.append("first")
def second():
log.append("second")
atexit.register(first)
atexit.register(second)
# Call the private runner used by the interpreter shutdown path in tests.
atexit._run_exitfuncs()
self.assertEqual(log, ["second", "first"])
log.clear()
atexit.register(first)
atexit.unregister(first)
atexit._run_exitfuncs()
self.assertEqual(log, [])
if __name__ == "__main__":
unittest.main()
ข้อจำกัดที่ควรรู้
atexit ไม่ใช่ที่พึ่งสำหรับ SIGKILL หรือไฟดับฉับพลัน งานที่ต้องทนพังกลางคันยังต้องใช้ journal หรือ transactional write อยู่ดี ผมใช้มันเป็นชั้นสุดท้ายสำหรับปิดไฟล์ล็อกและพิมพ์สรุปสั้นๆ ก่อนจบครับ
Recap
registerใส่คิว LIFOunregisterถอด handler ที่ยังไม่รัน- อย่าพึ่ง
atexitแทนการจัดการทรัพยากรใน scope ที่ควบคุมได้