Перезапуск файла Python без утраты аргументов и окружения
Повторный запуск выполняющегося файла
Под перезапуском Python файла понимается завершение текущего цикла работы и запуск того же файла для нового выполнения. Это действие помогает обновить конфигурацию, восстановить соединение или очистить временные данные после ошибки.
Как заменить текущий процесс на новый экземпляр скрипта?
Основной способ связан с функцией os.execv. Она подменяет образ текущего процесса новым интерпретатором Python. После вызова управление не возвращается в прежний код.
import os
import sys
attempt = int(os.environ.get('PY_RESTART_ATTEMPT', '0')) + 1
os.environ['PY_RESTART_ATTEMPT'] = str(attempt)
print('Запуск', attempt)
if attempt < 3:
script_path = os.path.abspath(__file__)
os.execv(sys.executable, [sys.executable, script_path] + sys.argv[1:])
else:
print('Достигнут предел перезапусков')Path python 2 (путь к python 2)
Вывод при запуске из терминала:
Запуск 1 Запуск 2 Запуск 3 Достигнут предел перезапусков
Python find directory (поиск директории)
Переменная окружения PY_RESTART_ATTEMPT передаёт следующему процессу количество уже выполненных запусков. Без ограничения os.execv будет перезапускать файл бесконечно. Данный вариант подходит для полной замены процесса без потерянных процессов-потомков.
Типичная проблема состоит в потере буферизованного вывода. Решение: перед вызовом добавить sys.stdout.flush() и sys.stderr.flush(). Также возможна ошибка, если путь в sys.argv[0] относительный, а рабочий каталог изменён. Для устойчивости применяется os.path.abspath(__file__). На Windows редкая ошибка прав доступа возникает при временной блокировке файла антивирусом. Повторный запуск после короткой паузы устраняет её.
Как запустить новую копию файла и завершить исходный процесс через subprocess?
Модуль subprocess создаёт отдельный процесс Python. Текущий процесс может завершиться сразу после запуска новой копии. Этот вариант применяют, когда копия файла должна работать отдельно от родительского процесса.
import os
import subprocess
import sys
def run_work():
print('Выполняю основную работу файла')
if __name__ == '__main__':
run_work()
if os.environ.get('PY_CHILD_STARTED') == '1':
print('Повторный запуск завершён')
sys.exit(0)
env = os.environ.copy()
env['PY_CHILD_STARTED'] = '1'
print('Родитель создаёт новую копию')
sys.stdout.flush()
script_path = os.path.abspath(__file__)
subprocess.Popen([sys.executable, script_path] + sys.argv[1:], env=env)
print('Родитель завершается')
sys.exit(0)
File does not exist python (проверка существования файла)
Вывод при запуске файла:
Выполняю основную работу файла Родитель создаёт новую копию Родитель завершается Выполняю основную работу файла Повторный запуск завершён
Python path configuration (конфигурация путей python)
Проверка переменной окружения не позволяет цепочке перезапусков повторяться бесконечно. В отличие от os.execv здесь создаётся полноценный отдельный процесс.
Если переменная окружения не проверяется, каждый новый процесс запускает ещё один, и так без остановки. Также дочерний процесс наследует открытые файловые дескрипторы. Для полного отделения от родительской группы часто передают параметр start_new_session=True, но его поддержка на Windows может отличаться.
Как перезапускать внешний файл с контролем кода возврата?
Внешний наблюдатель запускает worker.py, дожидается завершения и повторяет вызов при ненулевом коде. Такой подход подходит для служебных процессов, которые должны автоматически подниматься после сбоя.
import subprocess
import sys
import time
worker = 'worker.py'
max_attempts = 3
current = 0
while current < max_attempts:
current += 1
print('Попытка', current)
process = subprocess.Popen([sys.executable, worker])
code = process.wait()
if code == 0:
print('Worker успешно завершён')
break
time.sleep(1)
else:
print('Работа не завершена после', max_attempts, 'попыток')Python installation path (путь установки python)
Вывод, когда worker.py постоянно возвращает код 1:
Попытка 1 Попытка 2 Попытка 3 Работа не завершена после 3 попыток
Python path exists (проверка существования пути в python)
При короткой серии перезапусков стоит добавить паузу, иначе процесс может немедленно завершаться снова. Внешний наблюдатель не использует встроенную замену процесса и поэтому подходит для отладки и контроля повторных стартов.
Как повторить запуск Python файла из командной строки без изменения кода?
Командные циклы вызывают файл нужное число раз. Каждый вызов запускает интерпретатор заново после полного завершения предыдущей команды. Для Linux и macOS подходит bash цикл.
for i in {1..3}
do
python3 app.py
donePython file in folder (проверка существования файла в папке)
Для командной строки Windows применяется вариант с for.
for /l %i in (1,1,3) do python app.pyВ командной строке cmd используется %i, а в bat файле запись становится %%i. Такой способ полезен для периодического запуска после внешних изменений данных, когда код менять не требуется.
Командный цикл воспринимает любой код возврата как обычное завершение команды, если явно не проверять значение через errorlevel или $?. Это может скрыть факт ошибки в скрипте.
Перезапуск с добавленным флагом и сохранением исходных аргументов
Пример показывает передачу аргументов в следующий запуск. Первый процесс добавляет флаг --resume, а второй процесс завершает цепочку после обработки этого флага.
import os
import sys
if '--resume' in sys.argv:
print('Вторая стадия, аргументы:', sys.argv[1:])
sys.exit(0)
script_path = os.path.abspath(__file__)
arguments = [sys.executable, script_path] + sys.argv[1:] + ['--resume']
print('Первая стадия, аргументы:', sys.argv[1:])
sys.stdout.flush()
os.execv(sys.executable, arguments)Результат для команды python app.py mode=fast:
Первая стадия, аргументы: mode=fast Вторая стадия, аргументы: mode=fast --resume
Использование абсолютного пути к файлу делает команду независимой от смены рабочего каталога. Список sys.argv[1:] сохраняет пользовательские аргументы на протяжении всего перезапуска.
Ограниченная серия перезапусков с задержкой между попытками
Здесь переменная окружения хранит номер текущего запуска. Процесс выполняет код, делает паузу и заменяет себя новой копией. После третьего запуска цепочка останавливается.
import os
import sys
import time
max_runs = 3
run_number = int(os.environ.get('RESTART_RUN', '0')) + 1
os.environ['RESTART_RUN'] = str(run_number)
print('Номер запуска:', run_number)
if run_number >= max_runs:
print('Все запуски выполнены')
else:
time.sleep(1)
script_path = os.path.abspath(__file__)
os.execv(sys.executable, [sys.executable, script_path] + sys.argv[1:])Вывод:
Номер запуска: 1 Номер запуска: 2 Номер запуска: 3 Все запуски выполнены
Задержка перед заменой процесса предотвращает быстрое повторение кода при нестабильном состоянии системы.
Автоматический перезапуск при изменении конфигурационного файла
Внешний наблюдатель следит за временем изменения settings.ini. Если файл изменился, текущий child останавливается и запускается новая копия worker.py. Такой механизм востребован для файловых настроек без ручного вмешательства оператора.
import os
import subprocess
import sys
import time
worker_path = 'worker.py'
config_path = 'settings.ini'
def get_mtime():
return os.path.getmtime(config_path)
previous_mtime = get_mtime()
child = subprocess.Popen([sys.executable, worker_path])
try:
while True:
time.sleep(1)
current_mtime = get_mtime()
if current_mtime == previous_mtime:
continue
print('settings.ini изменён')
child.terminate()
child.wait()
child = subprocess.Popen([sys.executable, worker_path])
previous_mtime = current_mtime
except KeyboardInterrupt:
child.terminate()
child.wait()После изменения settings.ini в консоли появляется сообщение:
settings.ini изменён
Старая версия worker.py останавливается, а новая запускается с прежними параметрами окружения.
Запуск worker.py в отдельной директории с собственным окружением
Этот сценарий удобен, когда перезапускаемый файл находится в другом проекте или требует особого каталога. Параметр cwd задаёт рабочий каталог, env расширяет переменные окружения, а stdout и stderr направляются в общий лог.
import os
import subprocess
import sys
base_dir = '/home/user/project'
env = os.environ.copy()
env['APP_CONFIG'] = 'production'
log = open('restart.log', 'w')
worker = subprocess.Popen(
[sys.executable, 'worker.py'],
cwd=base_dir,
env=env,
stdout=log,
stderr=log
)
print('worker запущен с PID', worker.pid)Вывод:
worker запущен с PID 12345
Все сообщения worker.py попадают в restart.log, а процесс не зависит от текущего каталога родительской программы.
Повторное выполнение модуля через importlib.reload
В редких случаях вместо перезапуска файла нужно заново выполнить код уже импортированного модуля. Функция importlib.reload запускает модуль ещё раз в текущем процессе, не закрывая открытые соединения и не теряя переменные окружения.
import importlib
import my_module
print('Значение до перезагрузки:', my_module.VALUE)
my_module.VALUE = 100
my_module = importlib.reload(my_module)
print('Значение после перезагрузки:', my_module.VALUE)Если файл my_module.py содержит строку VALUE = 1, вывод будет:
Значение до перезагрузки: 1 Значение после перезагрузки: 1
Такой подход подходит для модулей с настройками, но не заменяет полный перезапуск процесса Python.