Python 标准库中 没有一个名为 external 的官方模块。

当你听到或看到 "external" 这个词时,它通常不是指一个具体的模块,而是指代一个概念或一系列实践,即“在 Python 程序中调用外部资源或程序”。
你的问题“python external模块”可以理解为以下几个核心方向:
- 执行外部命令/脚本:如何让你的 Python 脚本像在终端里一样运行其他命令行程序(如
ls,git,docker等)。 - 与外部程序进行交互:如何启动一个外部程序,并与其进行实时的数据交换(发送输入、读取输出)。
- 调用外部可执行文件:如何运行编译好的二进制文件(如
.exe,.sh脚本等)。 - 使用第三方库来简化外部调用:社区中有哪些优秀的库可以更优雅、更安全地完成上述任务。
下面我将围绕这四个方向,为你详细解释 Python 是如何与“外部”世界交互的。
执行外部命令(最常见的需求)
这是最常见的需求,比如你想在 Python 脚本中执行 git status 或 ls -l,Python 提供了多种方式,从简单到强大。

os.system() - 最简单,但功能有限
这是最直接的方式,它会在一个子 shell 中执行你的命令,并返回命令的退出状态码。
import os
# 执行一个简单的命令,打印结果到终端
# 返回值是命令执行后的退出码 (0 表示成功)
return_code = os.system('echo "Hello from Python"')
print(f"命令执行退出码: {return_code}")
# 执行一个带参数的命令
os.system('ls -l')
缺点:
- 无法获取命令的输出:
os.system()只能将命令的输出打印到标准输出(你的终端),无法在 Python 程序中捕获和处理这个输出。 - 不安全:如果命令参数来自用户输入,很容易造成命令注入漏洞。
- 功能单一:无法处理复杂的交互。
subprocess 模块 - 现代、强大、推荐
subprocess 是 Python 官方推荐用于管理子进程的模块,功能非常强大,可以替代旧的 os.system, os.spawn 等。
subprocess.run() - 推荐的通用方法
这是 Python 3.5+ 引入的现代化接口,非常灵活和安全。

import subprocess
# --- 示例1: 执行命令并获取输出 ---
# capture_output=True 会捕获标准输出和标准错误
# text=True 会将输出解码为字符串(默认是字节)
# check=True 如果命令返回非零退出码,会抛出 CalledProcessError 异常
try:
result = subprocess.run(['ls', '-l'], capture_output=True, text=True, check=True)
# result.stdout 是命令的标准输出
print("命令输出:")
print(result.stdout)
# result.stderr 是命令的标准错误
# result.returncode 是退出码
print(f"退出码: {result.returncode}")
except subprocess.CalledProcessError as e:
print(f"命令执行失败: {e}")
print(f"错误输出: {e.stderr}")
# --- 示例2: 安全地处理用户输入(防止命令注入)---
# 使用列表形式传递命令和参数,而不是字符串
user_input = "my_file.txt"
command = ['cat', user_input] # 这样是安全的
# command = f'cat {user_input}' # 这样是危险的!user_input 是 "my_file.txt; rm -rf /",后果不堪设想
try:
result = subprocess.run(command, capture_output=True, text=True, check=True)
print("\n文件内容:")
print(result.stdout)
except FileNotFoundError:
print(f"错误: 文件 {user_input} 不存在")
except subprocess.CalledProcessError as e:
print(f"命令执行失败: {e.stderr}")
subprocess.Popen() - 更底层的控制
当你需要与子进程进行实时交互时(比如启动一个交互式 shell 或一个持续运行的程序),Popen 是更好的选择,它不会像 run() 那样等待命令执行完毕。
import subprocess
# 启动一个子进程
proc = subprocess.Popen(['ping', '-c', '5', 'google.com'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
# 实时读取输出
while True:
output = proc.stdout.readline()
if output == '' and proc.poll() is not None:
break
if output:
print(output.strip())
# 等待进程结束,并获取返回码
return_code = proc.wait()
print(f"\nPing 命令执行完毕,退出码: {return_code}")
与外部程序进行交互
使用 subprocess.Popen 可以实现交互,我们以 bc (一个命令行计算器) 为例。
import subprocess
# 启动 bc 进程
proc = subprocess.Popen(['bc'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
# 发送输入 "2 + 2",然后发送 "quit" 来退出
proc.stdin.write("2 + 2\n")
proc.stdin.write("quit\n")
proc.stdin.close() # 关闭输入流,告诉 bc 没有更多输入了
# 读取所有输出
stdout, stderr = proc.communicate()
print("bc 计算结果:")
print(stdout) # 应该会输出 "4\n"
调用外部可执行文件
这和执行命令本质上是一样的,无论是 .exe 文件、.sh 脚本还是其他任何可执行文件,Python 都可以通过 subprocess 模块来调用。
在 Windows 上调用 .exe 文件:
import subprocess # 假设你有一个 my_app.exe 文件 subprocess.run(['my_app.exe', '--input', 'data.txt'])
在 Linux/macOS 上调用 .sh 脚本:
import subprocess # 脚本需要有执行权限 (chmod +x my_script.sh) subprocess.run(['./my_script.sh', 'arg1', 'arg2'])
使用第三方库简化外部调用
除了标准库,社区也开发了许多优秀的第三方库来处理外部调用,它们通常提供了更简洁的 API 或特定领域的功能。
sh 库 - 一个非常流行的替代品
sh 库的设计哲学是让调用外部命令就像调用普通 Python 函数一样自然。
安装:
pip install sh
使用示例:
from sh import git, ls
# 像调用函数一样调用 git
print(gl="en") # git status --porcelain
# 获取输出
try:
output = ls("-l")
print(output)
except sh.ErrorReturnCode as e:
print(f"命令执行失败: {e.stderr}")
plumbum 库 - 功能强大的工具链
plumbum 是一个功能更全面的库,不仅包含命令调用,还提供了路径操作、进程管理等工具。
安装:
pip install plumbum
使用示例:
from plumbum import local, FG
# FG 表示将子进程的输入输出连接到当前终端(前台运行)
# local.path("ls") -l | FG
# 也可以捕获输出
from plumbum import Command
ls = Command("ls")
try:
output = ls("-l")
print(output)
except local.ProcessExecutionError as e:
print(f"命令执行失败: {e.stderr}")
总结与最佳实践
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
os.system() |
简单直接,无需导入 | 无法获取输出,不安全,功能弱 | 快速执行简单命令,不关心结果 |
subprocess.run() |
现代、安全、灵活,推荐首选 | 相对 os.system 稍显复杂 |
绝大多数情况下的首选,需要获取输出、处理错误等 |
subprocess.Popen() |
功能最强大,支持实时交互 | API 最复杂,需要手动管理进程生命周期 | 需要与子进程持续交互(如 shell、游戏服务器) |
sh / plumbum |
语法简洁,易于使用 | 需要额外安装,可能引入依赖 | 需要在大量地方调用外部命令,追求代码简洁性的项目 |
核心建议:
- 忘记
os.system():除非你只是想在脚本里快速打印个日志,否则不要用它。 - 从
subprocess.run()开始:对于 99% 的外部命令调用需求,subprocess.run()都能完美胜任,它提供了安全、可控和现代化的接口。 - 在需要交互时用
Popen():当你发现run()无法满足需求(比如需要一边输入一边等待输出)时,再考虑使用Popen()。 - 考虑第三方库:如果你的项目核心逻辑就是调用大量外部命令,并且希望代码更优雅,
sh或plumbum是非常好的选择。
