ماژول atexit پایتون
ماژول atexit پایتون یک رابط ساده برای ثبت توابع فراهم می کند تا زمانی که برنامه به طور معمول بسته می شود فراخوانی شود. ماژول sys یک تابع به نام sys.exitfunc را نیز فراهم می کند، اما تنها یک تابع را می توان در آنجا ثبت کرد. رجیستری atexit می تواند توسط چندین ماژول و کتابخانه به طور همزمان استفاده شود.
یک مثال ساده از ثبت یک تابع از طریق atexit.register به شکل زیر است:
import atexit
def all_done():
print 'all_done()'
print 'Registering'
atexit.register(all_done)
print 'Registered'
از آنجایی که برنامه کار دیگری انجام نمی دهد، تابع all_done بلافاصله فراخوانی می شود:
$ python atexit_simple.py
Registering
Registered
all_done()
همچنین امکان ثبت بیش از یک تابع و ارسال آرگومان نیز وجود دارد. این ویژگی میتواند برای قطع ارتباط از پایگاههای داده، حذف فایلهای موقت و غیره مفید باشد.
import atexit
def my_cleanup(name):
print 'my_cleanup(%s)' % name
atexit.register(my_cleanup, 'first')
atexit.register(my_cleanup, 'second')
atexit.register(my_cleanup, 'third')
توجه داشته باشید که ترتیبی که توابع exit فراخوانی می شوند، برعکس ترتیبی است که آنها ثبت می شوند. این ویژگی اجازه می دهد تا ماژول ها به ترتیب معکوس که از آن وارد شده اند پاک شوند، که باعث کاهش تضادهای وابستگی می شود.
$ python atexit_multiple.py
my_cleanup(third)
my_cleanup(second)
my_cleanup(first)
# چه زمانی توابع atexit فراخوانی نمی شوند؟
توابع ثبت شده با atexit در موارد زیر فراخوانی نمی شوند:
1. برنامه با ارسال یک سیگنال متوقف شود
2. برنامه با تابع os._exit متوقف شود
3. یک خطای مفسر رخ دهد
برای نشان دادن برنامه ای که از طریق سیگنال متوقف می شود، می توانیم از یک مثال استفاده کنیم. در این مثال دو فایل وجود دارد که یکی برای فرآیند والد و دیگری برای فرآیند فرزند به کار میرود. فرآیند والد، فرآیند فرزند را اجرا کرده، یک مکث ایجاد کرده و در نهایت آن را متوقف میکند:
import os
import signal
import subprocess
import time
proc = subprocess.Popen('atexit_signal_child.py')
print 'PARENT: Pausing before sending signal...'
time.sleep(1)
print 'PARENT: Signaling child'
os.kill(proc.pid, signal.SIGTERM)
فرآیند فرزند یک atexit راه اندازی می کند تا ثابت کند که آن فراخوانی نشده است.
import atexit
import time
import sys
def not_called():
print 'CHILD: atexit handler should not have been called'
print 'CHILD: Registering atexit handler'
sys.stdout.flush()
atexit.register(not_called)
print 'CHILD: Pausing to wait for signal'
sys.stdout.flush()
time.sleep(5)
وقتی این برنامه را اجرا میکنید خروجی باید به شکل زیر باشد:
$ python atexit_signal_parent.py
CHILD: Registering atexit handler
CHILD: Pausing to wait for signal
PARENT: Pausing before sending signal...
PARENT: Signaling child
توجه داشته باشید که فرآیند فرزند پیام نوشته شده در not_called را چاپ نمی کند.
به طور مشابه، اگر برنامهای مسیر خروج عادی را دور بزند، میتواند از فراخوانی توابع atexit جلوگیری کند.
import atexit
import os
def not_called():
print 'This should not be called'
print 'Registering'
atexit.register(not_called)
print 'Registered'
print 'Exiting...'
os._exit(0)
از آنجایی که ما به جای خروج عادی، os._exit() را فراخوانی می کنیم، callback فراخوانی نمی شود.
$ python atexit_os_exit.py
اگر به جای آن از sys.exit() استفاده کرده بودیم، توابع همچنان فراخوانی می شدند.
import atexit
import sys
def all_done():
print 'all_done()'
print 'Registering'
atexit.register(all_done)
print 'Registered'
print 'Exiting...'
sys.exit()
برنامه را اجرا کنید:
$ python atexit_sys_exit.py
Registering
Registered
Exiting...
all_done()
ارسال نظر