下面我将从最简单到最强大,详细介绍几种主流的方法,并附上代码示例和适用场景。

核心概念
在开始之前,需要理解一个关键点:你是在执行一个 Python 模块(脚本),还是在执行一个普通的系统命令?
- 执行 Python 模块:运行一个
.py文件。python my_script.py。 - 执行系统命令:运行任何在终端/命令行中可以执行的命令,如
ls -l(Linux/macOS) 或dir(Windows)。
Python 的 subprocess 模块是处理这些任务最现代、最灵活、最强大的工具,下面我们主要以它为例。
subprocess.run() (推荐,Python 3.5+)
这是目前最推荐、最通用的方法,它启动一个子进程来执行命令,并等待其完成。
执行一个简单的 Python 脚本
假设你有一个名为 hello.py 的文件:

hello.py
import sys
import time
print(f"Hello from script! My PID is {os.getpid()}")
print(f"Arguments received: {sys.argv}")
time.sleep(5) # 模拟一个耗时操作
print("Script finished.")
你想从另一个 Python 脚本(main.py)中执行它。
main.py
import subprocess
import os
# --- 执行一个 Python 脚本 ---
# 使用 python3 命令来执行 hello.py
# 注意:hello.py 需要参数,可以直接在列表后面添加
command = ["python3", "hello.py", "arg1", "arg2"]
print(f"Executing command: {' '.join(command)}")
# 使用 subprocess.run()
# check=True: 如果命令返回非零退出码(表示失败),则会引发 CalledProcessError 异常
# capture_output=True: 捕获标准输出和标准错误
# text=True: 将输出解码为文本(默认为字节)
# timeout=10: 设置超时时间(秒),超时会引发 TimeoutExpired 异常
try:
result = subprocess.run(
command,
check=True,
capture_output=True,
text=True,
timeout=10
)
# 命令执行成功
print("\n--- Command executed successfully! ---")
print(f"Return code: {result.returncode}")
print("Standard Output:")
print(result.stdout)
except subprocess.CalledProcessError as e:
# 命令执行失败(返回非零码)
print(f"\n--- Command failed with return code {e.returncode} ---")
print("Standard Error:")
print(e.stderr)
except subprocess.TimeoutExpired as e:
# 命令执行超时
print(f"\n--- Command timed out after 10 seconds! ---")
print("Stdout (if any):")
print(e.stdout)
print("Stderr (if any):")
print(e.stderr)
except FileNotFoundError:
# python3 命令未找到
print("Error: 'python3' command not found. Is it installed and in your PATH?")
如何运行:

# 确保 hello.py 和 main.py 在同一目录下 python3 main.py
执行系统命令(如 ls 或 dir)
执行系统命令的方式完全相同,只是命令列表的第一个元素不是 python3。
示例:在 Linux/macOS 上执行 ls -l
import subprocess
command = ["ls", "-l"]
try:
result = subprocess.run(command, check=True, capture_output=True, text=True)
print("Command executed successfully!")
print("Output:")
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"Command failed: {e.stderr}")
os.system() (简单但过时)
这是一个非常老派的方法,直接调用系统的 shell 来执行命令,它简单易用,但功能有限,不推荐在新代码中使用。
特点:
- 直接在父进程中执行,无法获取命令的输出(除非重定向到文件)。
- 无法处理超时。
- 容易受到 shell 注入攻击(如果命令参数来自用户输入)。
import os
# 执行一个简单的命令
# 返回的是命令执行后的退出码
return_code = os.system("echo 'Hello from os.system'")
print(f"Return code: {return_code}")
# 执行一个 Python 脚本
# 注意:如果脚本路径或参数包含空格或特殊字符,可能会有问题
os.system("python3 hello.py arg1 arg2")
os.popen() (旧版管道)
os.popen 打开一个管道,允许你通过文件对象来读取命令的输出或写入输入。
特点:
- 可以获取命令的输出。
- 功能比
os.system强,但比subprocess弱。 - Python 3.3+ 中已废弃,不推荐使用。
import os
# 执行命令并读取输出
# 'r' 表示以读取模式打开管道
with os.popen('ls -l') as pipe:
output = pipe.read()
print("Output from os.popen:")
print(output)
subprocess.Popen() (最灵活)
subprocess.run() 实际上是 subprocess.Popen() 的一个高级封装,当你需要更精细的控制时,比如与子进程进行实时交互、并发运行多个进程等,就应该直接使用 Popen。
Popen 是异步的,它会立即返回一个 Popen 对象,而不会等待子进程结束,你需要手动调用 communicate()、wait() 或 poll() 来管理进程。
import subprocess
import time
print("Starting a long-running process with Popen...")
# 启动进程
# Popen 不会阻塞,它会立即返回
process = subprocess.Popen(
["python3", "hello.py", "from_popen"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# 主线程可以做其他事情
print("Main program is doing other work...")
time.sleep(2)
# 等待进程结束并获取输出
# communicate() 会等待进程结束,并返回 (stdout, stderr) 的元组
# 它还会正确处理子进程的管道,避免死锁
stdout, stderr = process.communicate()
print("\n--- Popen process finished ---")
print(f"Return code: {process.returncode}")
print("Standard Output:")
print(stdout)
if stderr:
print("Standard Error:")
print(stderr)
import (Pythonic 的方式)
如果你的目标只是调用另一个 Python 脚本中的函数或使用其类,而不是完全作为独立进程运行,那么最好的方法是直接导入它。
my_module.py
def greet(name):
return f"Hello, {name} from my_module!"
def add(a, b):
return a + b
main.py
import my_module
# 直接调用函数,就像调用本地函数一样
message = my_module.greet("Alice")
print(message)
result = my_module.add(10, 20)
print(f"10 + 20 = {result}")
优点:
- 高效:没有创建新进程的开销。
- 简单:代码更清晰,符合 Python 的哲学。
- 共享内存:可以直接共享变量和数据结构。
缺点:
- 共享全局状态:两个脚本运行在同一个解释器中,会共享全局命名空间,可能导致意外的副作用。
- 无法隔离:一个脚本的错误会影响整个程序。
总结与选择指南
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
subprocess.run() |
绝大多数情况下的首选,执行命令、运行脚本、获取输出、处理错误。 | 现代、安全、功能强大、接口清晰、支持超时。 | 相对复杂一点,但非常值得学习。 |
subprocess.Popen() |
需要高级控制,如并发、实时交互、管理多个子进程。 | 最灵活、功能最全、异步。 | 代码更复杂,需要手动管理进程生命周期。 |
import |
想在当前程序中复用另一个 Python 文件的代码(函数、类)。 | 最高效、最简单、Pythonic。 | 共享全局状态,无法隔离,不适用于需要独立环境的场景。 |
os.system() |
简单的一次性命令,且不关心输出和错误。 | 极其简单。 | 功能弱、不安全(易受注入)、无法获取输出、已过时。 |
os.popen() |
需要获取命令输出的旧代码中可能见到。 | 比 os.system 强。 |
已废弃,功能不如 subprocess。 |
简单决策流程:
-
我只是想用另一个
.py文件里的函数?- 用
import。
- 用
-
我需要运行一个独立的
.py脚本,或者一个系统命令(如git,docker),并获取它的输出和结果?- 用
subprocess.run()。 这是你的默认选择。
- 用
-
我需要同时运行多个命令,或者与一个长时间运行的进程进行实时对话吗?
- 用
subprocess.Popen()。
- 用
