How to Restart Python Scripts
Restarting a Python script from within itself can be useful for various reasons: recovering from unrecoverable errors, reloading configuration, or implementing a simple update mechanism.
This guide explains different methods to restart a Python script, emphasizing the recommended approach (os.execv()
) and outlining the pros and cons of alternatives.
Restarting with os.execv()
(Recommended)
The os.execv()
function is the best and safest way to restart a Python script. It replaces the current process with a new one, running the same script. This is much cleaner than launching a new, separate process.
import os
import sys
import time # Import the time module
def restart():
print('Restarting script in 3 seconds...') # Clearer output.
time.sleep(3) # Added delay
os.execv(sys.executable, [sys.executable] + sys.argv)
restart()
print("This line will NOT be reached in the original process.") # Clarified comment
sys.executable
: This variable holds the absolute path to the Python interpreter (e.g.,/usr/bin/python3
orC:\Python39\python.exe
).sys.argv
: This is a list of the command-line arguments passed to the script.sys.argv[0]
is the script name itself. We include this so that any arguments your script uses are passed to the restarted version.os.execv(executable, args)
: This is the core of the restart.executable
: The path to the new program to execute (our Python interpreter).args
: A list of strings representing the arguments to the new program. We're essentially building the commandpython your_script.py [any original arguments]
.time.sleep(3)
: This adds a 3-second delay before restarting. This is often useful to prevent rapid restart loops in case of errors.
After os.execv()
is called, no further code in the original process is executed. It's a complete process replacement.
You might need to adjust the Python executable name for different systems:
# Often needed on macOS/Linux
os.execv(sys.executable, ['python3'] + sys.argv)
# Often works on Windows
os.execv(sys.executable, ['py'] + sys.argv)
Restarting with os.system()
(Not Recommended)
os.system()
executes a command in a new subshell. While you can use it to start a new instance of your script, it's strongly discouraged for restarting.
import os
import time
print('Restarting using os.system()...')
time.sleep(3)
os.system('python main.py') # Starts a NEW process.
print("This WILL print, but in the *original* process.") # added a warning
Why os.system()
is bad for restarting:
- Two Processes: You end up with two instances of your script running: the original and the new one. This can lead to resource contention, unexpected behavior, and difficulty managing the processes.
- No Clean Exit: The original process doesn't terminate; it continues running after
os.system()
completes. - Resource Leaks: The original process may hold onto resources (files, network connections, etc.) that the new process needs.
Restarting a Script Indefinitely
To restart a script continuously, combine os.execv()
with a while True
loop:
import os
import sys
import time
while True:
print('Running script...')
time.sleep(3) # Simulate work being done
print('Restarting...')
os.execv(sys.executable, [sys.executable] + sys.argv)
# Code here will NEVER be reached. os.execv() replaces the process.
Be extremely careful with infinite restart loops. If your script has an error that causes it to crash quickly, you can create a very fast loop that consumes system resources. Always include a delay (like time.sleep()
) and robust error handling.
Restarting with psutil
(Advanced)
The psutil
library provides more control over processes. It's useful for gracefully restarting a script, ensuring file handles and connections are closed. This is a more advanced technique.
import sys
import os
import psutil
import time
def restart_script():
try:
p = psutil.Process(os.getpid())
for handler in p.open_files() + p.connections():
try: # Add a try/except to close each handle.
os.close(handler.fd)
except Exception as e:
print(f"Error closing handle: {e}")
except Exception as e:
print(e)
python = sys.executable
print("Restarting in 3 seconds...")
time.sleep(3)
os.execl(python, python, *sys.argv)
print('Running...')
restart_script()
print("This will NEVER be reached.")
- The code attempts to close all file descriptors and network connections before calling
os.execl
. The newtry/except
block is very important to prevent the program from crashing if a file descriptor can not be closed.
Restarting with a Bash Script (Platform-Specific)
For Unix-like systems (Linux, macOS), you can use a bash script to kill any running instances of your script and then start a new one:
#!/bin/bash
pkill -f main.py # Kill any existing processes running main.py. CAREFUL!
python main.py & # Run in the background
import os
import subprocess
# Make the bash script executable if it's not
subprocess.run(['chmod', '+x', 'restart-script.sh'], check=False) # Use check=False because chmod won't work on windows
print('Running main.py...')
os.execl('./restart-script.sh', '&') # Execute the script
print("This line will NEVER be reached.")
Important Considerations:
pkill -f main.py
is DANGEROUS: This command kills any process whose command line contains "main.py". If other Python scripts have "main.py" in their command line (e.g., an editor running the script), they will be killed too. Use with extreme caution. A better solution would be to manage a PID file.- Portability: This approach is not cross-platform. It will only work on systems with
bash
andpkill
. - Background Process: The
&
at the end of thepython main.py
line in the bash script runs the new instance in the background. This might not be what you want.