Вот пример того, как это можно реализовать с помощью pyinotify (т. Е. В Linux).
from importlib import import_module
class RestartingLauncher:
def __init__(self, module_name, start_function, stop_function, path="."):
self._module_name = module_name
self._filename = '%s.py' % module_name
self._start_function = start_function
self._stop_function = stop_function
self._path = path
self._setup()
def _setup(self):
import pyinotify
self._wm = pyinotify.WatchManager()
self._notifier = pyinotify.ThreadedNotifier(
self._wm, self._on_file_modified)
self._notifier.start()
# We monitor the directory (instead of just the file) because
# otherwise inotify gets confused by editors such a Vim.
flags = pyinotify.EventsCodes.OP_FLAGS['IN_MODIFY']
wdd = self._wm.add_watch(self._path, flags)
def _on_file_modified(self, event):
if event.name == self._filename:
print "File modification detected. Restarting application..."
self._reload_request = True
getattr(self._module, self._stop_function)()
def run(self):
self._module = import_module(self._module_name)
self._reload_request = True
while self._reload_request:
self._reload_request = False
reload(self._module)
getattr(self._module, self._start_function)()
print 'Bye!'
self._notifier.stop()
def launch_app(module_name, start_func, stop_func):
try:
import pyinotify
except ImportError:
print 'Pyinotify not found. Launching app anyway...'
m = import_module(self._module_name)
getattr(m, start_func)()
else:
RestartingLauncher(module_name, start_func, stop_func).run()
if __name__ == '__main__':
launch_app('example', 'main', 'force_exit')
Параметры в вызове launch_app - это имя файла (без ".py"),функция для запуска выполнения и функция, которая каким-то образом останавливает выполнение.
Вот глупый пример «приложения», которое можно (повторно) запустить с использованием предыдущего кода:
run = True
def main():
print 'in...'
while run: pass
print 'out'
def force_exit():
global run
run = False
В типичном приложении, где вы хотели бы использовать это, вы, вероятно, имели бы какой-то основной цикл.Вот более реальный пример для приложения на базе GLib / GTK +:
from gi.repository import GLib
GLib.threads_init()
loop = GLib.MainLoop()
def main():
print "running..."
loop.run()
def force_exit():
print "stopping..."
loop.quit()
Та же концепция работает для большинства других циклов (Clutter, Qt и т. Д.).
Мониторинг нескольких файлов кода (т.е. все файлы, которые являются частью приложения) и устойчивость к ошибкам (например, печать исключений и ожидание в цикле простоя, пока код не будет исправлен, а затем запуск его снова) оставлены в качестве упражнений для читателя:).
Примечание. Весь код в этом ответе выпущен под лицензией ISC (в дополнение к Creative Commons).