在 Python 程序中调用另一个 Python 文件,本质上就是执行该文件中的代码,根据不同的需求,主要有以下几种方法,每种方法都有其特定的应用场景。

核心概念:模块与包
要理解 Python 的基本组织结构:
- 模块:一个
.py文件就是一个模块,模块中定义的函数、类和变量都可以被其他程序引入。 - 包:一个包含
__init__.py文件的目录,用于组织多个相关的模块。
当你调用一个 Python 文件时,你通常是在将其作为一个模块来导入。
使用 import 语句 (最常用、最推荐)
这是最标准、最 Pythonic 的方式,它会执行被导入文件(模块)中的所有顶层代码,并将其中的函数、类、变量等加载到当前命名空间中。
场景1:导入整个模块
假设你有两个文件,在同一目录下:

my_module.py (被调用的文件)
# 这是一个模块,包含了可重用的代码
def greet(name):
"""一个简单的问候函数"""
print(f"Hello, {name}!")
# 这是一个变量
VERSION = "1.0"
# 这部分代码会在模块被导入时立即执行
print(f"模块 {__name__} 已被导入")
main.py (主程序文件)
# 导入整个模块
import my_module
# 使用模块中的函数
my_module.greet("Alice")
# 使用模块中的变量
print(f"当前版本是: {my_module.VERSION}")
如何运行:
在终端中,进入这两个文件所在的目录,然后运行 main.py:
python main.py
输出结果:

模块 my_module 已被导入 <-- 这是 my_module.py 中的 print 语句
Hello, Alice!
当前版本是: 1.0
关键点:
- 使用
import my_module后,必须通过模块名.成员名(如my_module.greet) 来访问。 - 一个模块只会被导入一次,即使你在
main.py中import my_module一百次,my_module.py中的顶层代码也只会执行一次。
场景2:为模块指定别名 (推荐用于长模块名)
如果模块名很长,或者容易与当前代码中的变量名冲突,可以指定一个简短的别名。
main.py
import my_module as mm # 将 my_module 别名为 mm
# 使用别名来访问模块成员
mm.greet("Bob")
print(f"版本: {mm.VERSION}")
场景3:从模块中导入特定成员
如果你只需要模块中的某一个或几个函数或变量,可以使用 from ... import ... 语法。
main.py
# 只导入 greet 函数和 VERSION 变量
from my_module import greet, VERSION
# 直接使用导入的成员,无需模块名前缀
greet("Charlie")
print(f"版本: {VERSION}")
# 这样做会报错,因为 my_module 这个名字没有被导入
# my_module.greet("David") # NameError: name 'my_module' is not defined
场景4:导入模块中的所有成员 (不推荐)
使用 from ... import * 会将模块中所有不以下划线 _ 开头的名字导入到当前命名空间。
main.py
from my_module import *
greet("Eve")
print(f"版本: {VERSION}")
为什么不推荐?
- 命名空间污染:它会把你导入的模块中的所有东西都扔到当前文件里,容易和你自己的变量、函数名发生冲突,导致难以发现的错误。
- 可读性差:阅读代码的人无法一眼看出
greet函数是定义在当前文件还是从哪个模块导入的。 - 维护困难:
my_module.py更新了,增加了新的函数,可能会意外地覆盖掉你当前文件中的同名函数。
使用 exec() 或 eval() (不推荐,有风险)
exec() 可以执行一个字符串形式的 Python 代码。eval() 可以计算一个字符串表达式的值。
another_script.py
def another_function():
print("这是另一个脚本中的函数")
print("执行 another_script.py 的顶层代码")
main.py
# 使用 exec() 执行另一个文件
with open('another_script.py', 'r', encoding='utf-8') as f:
script_content = f.read()
exec(script_content)
# 调用被 exec 执行后定义的函数
another_function()
为什么不推荐?
- 安全风险:
another_script.py文件的内容不受你控制(例如来自用户输入),exec()可能会执行恶意代码,非常危险。 - 调试困难:在
exec()内部发生的错误,其堆栈跟踪会非常不清晰。 - 破坏命名空间:
exec()会直接在当前的局部或全局命名空间中执行代码,容易造成变量污染。
仅在特殊情况下使用,例如动态加载和执行插件,并且你必须完全信任源文件。
使用 subprocess 模块 (作为独立进程运行)
如果你想将另一个 Python 文件完全独立地运行(就像在命令行中输入 python script.py 一样),可以使用 subprocess 模块,这会创建一个新的进程来执行脚本。
subprocess_script.py
import os
import sys
print(f"子进程的 PID (进程ID): {os.getpid()}")
print(f"子进程接收到的参数: {sys.argv}")
print("这是一个独立运行的子进程。")
main.py
import subprocess
import sys
# 方式1: 运行脚本,不获取输出
print("--- 运行方式1: 不获取输出 ---")
subprocess.run([sys.executable, 'subprocess_script.py'])
# 方式2: 运行脚本,并捕获其标准输出
print("\n--- 运行方式2: 捕获输出 ---")
result = subprocess.run(
[sys.executable, 'subprocess_script.py', 'arg1', 'arg2'], # 传递命令行参数
capture_output=True, # 捕获标准输出和标准错误
text=True, # 将输出解码为文本
check=True # 如果脚本返回非零退出码,则抛出异常
)
print(f"子进程的返回码: {result.returncode}")
print(f"子进程的标准输出:\n{result.stdout}")
# print(f"子进程的标准错误:\n{result.stderr}") # 如果有错误的话
如何运行:
python main.py
输出结果:
--- 运行方式1: 不获取输出 ---
子进程的 PID (进程ID): 12345
子进程接收到的参数: ['subprocess_script.py']
这是一个独立运行的子进程。
--- 运行方式2: 捕获输出 ---
子进程的 PID (进程ID): 12346
子进程接收到的参数: ['subprocess_script.py', 'arg1', 'arg2']
这是一个独立运行的子进程。
子进程的返回码: 0
子进程的标准输出:
子进程的 PID (进程ID): 12346
子进程接收到的参数: ['subprocess_script.py', 'arg1', 'arg2']
这是一个独立运行的子进程。
适用场景:
- 你想完全隔离两个程序的运行环境。
- 你需要将另一个程序作为子进程来管理(启动、停止、监控)。
- 你想将另一个 Python 脚本当作一个独立的命令行工具来使用。
总结与选择指南
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
import |
标准、安全、高效,能重用代码,是 Python 的核心机制。 | 需要遵循模块化设计。 | 绝大多数情况,当你想在一个程序中复用另一个文件的代码(函数、类、变量)时。 |
exec() |
灵活,可以动态执行代码字符串。 | 安全风险高,调试困难,破坏命名空间。 | 极少使用,仅在需要动态执行完全可信的代码片段时(如配置文件中的逻辑)。 |
subprocess |
完全隔离,可以独立运行程序,能获取命令行输出。 | 进程间通信复杂,开销大。 | 当你需要将另一个脚本作为独立任务或外部工具来执行时,例如运行测试、部署脚本等。 |
除非有特殊需求(如需要完全隔离或执行独立任务),否则请始终优先使用
import语句来调用其他 Python 文件。 这是 Python 设计的初衷,也是最安全、最清晰、最符合社区规范的方式。
