核心概念:模块
在 Python 中,任何一个 .py 文件都可以被称为一个 模块,当你在一个脚本中导入另一个脚本时,你实际上是在导入那个脚本所定义的模块。

你有一个文件 my_module.py:
# my_module.py
def greet(name):
print(f"Hello, {name}!")
def add(a, b):
return a + b
这个文件 my_module.py 就是一个模块。
import 语句(最常用、最推荐)
这是最标准、最 Pythonic 的方式,它将整个模块作为一个对象导入。
导入整个模块
使用 import module_name 语法。

调用脚本 (main.py):
# main.py
import my_module # 导入 my_module.py 文件
# 使用模块名.函数名 的方式来调用
my_module.greet("Alice") # 输出: Hello, Alice!
result = my_module.add(5, 3)
print(f"The sum is: {result}") # 输出: The sum is: 8
如何运行:
确保 main.py 和 my_module.py 在同一个目录下,然后在终端运行:
python main.py
优点:
- 命名空间清晰:所有函数和变量都必须通过
module_name.前缀来访问,避免了命名冲突。 - 可读性强:一眼就能看出函数来自哪个模块。
- 标准做法:这是 Python 社区推荐的最佳实践。
为模块指定别名
如果模块名很长或者为了方便,可以给它起一个短别名。
调用脚本 (main.py):
# main.py
import my_module as mm # 将 my_module 别名为 mm
# 使用别名来调用
mm.greet("Bob") # 输出: Hello, Bob!
result = mm.add(10, 20)
print(f"The sum is: {result}") # 输出: The sum is: 30
优点:
- 代码更简洁,尤其在多次调用模块内函数时。
- 常用于导入第三方库,如
import pandas as pd。
从模块中导入特定函数/变量
如果你只需要模块中的某一个或几个函数,可以使用 from ... import ... 语法。
调用脚本 (main.py):
# main.py
from my_module import greet, add # 只导入 greet 和 add 函数
# 直接使用函数名,无需模块名前缀
greet("Charlie") # 输出: Hello, Charlie!
result = add(100, 200)
print(f"The sum is: {result}") # 输出: The sum is: 300
优点:
- 代码更简洁,无需写前缀。
- 只导入需要的内容,可能略微减少内存占用(虽然现代 Python 解释器优化得很好,这点差别不大)。
⚠️ 注意(缺点):
- 命名冲突:如果当前脚本中已经有了一个同名的函数,导入后会覆盖它,如果
main.py里也定义了一个add函数,from my_module import add之后,main.py里的add就会被my_module的add替换。
导入模块中的所有内容
使用 from ... import * 会导入模块中所有不以下划线 _ 开头的公共名称。
调用脚本 (main.py):
# main.py
from my_module import * # 导入 my_module 中的所有公共内容
# 直接使用所有导入的函数
greet("David") # 输出: Hello, David!
print(add(2, 2)) # 输出: 4
⚠️ 强烈不推荐! 这种方式严重破坏命名空间,极易导致难以追踪的命名冲突,是“坏味道”的代码,请尽量避免使用。
exec() 函数(动态执行,需谨慎)
exec() 可以执行一个字符串形式的 Python 代码,你可以用它来读取并执行另一个 .py 文件的内容。
调用脚本 (main.py):
# main.py
with open('my_module.py', 'r', encoding='utf-8') as f:
script_content = f.read()
作为字符串来执行
exec(script_content)
# 注意:exec执行后,my_module.py中的函数和变量会直接进入当前命名空间
greet("Eve") # 这可以直接调用,因为exec已经执行了greet的定义
print(add(3, 5)) # 同理
优点:
- 动态性:可以在运行时决定执行哪个脚本,文件名甚至可以是一个变量。
- 灵活性高:可以动态修改代码后再执行。
缺点和风险:
- 安全性极差:如果执行的文件来自不可信的来源(如用户上传),
exec()可能会执行恶意代码,导致安全漏洞。 - 破坏命名空间:和
from ... import *类似,它会将执行文件中的所有变量和函数都注入到当前作用域,造成混乱。 - 调试困难:错误堆栈信息会比较复杂,难以定位。
适用场景:
非常罕见,通常用于动态代码生成或特定领域的脚本引擎。99% 的情况下,你都应该使用 import。
subprocess 模块(作为独立进程运行)
这种方式不是在当前 Python 解释器中“导入”模块,而是像在命令行中一样,“调用”另一个 Python 脚本让它作为一个新的、独立的进程运行,主脚本会等待子脚本执行完毕,然后继续执行。
这适用于需要完全隔离环境或捕获子脚本的输出(标准输出/标准错误)的场景。
子脚本 (child_script.py):
# child_script.py
import sys
import time
print("Child script started.")
print(f"Child script received arguments: {sys.argv}") # sys.argv 可以获取命令行参数
for i in range(3):
print(f"Child is running... {i+1}/3")
time.sleep(1)
print("Child script finished.")
主脚本 (main.py):
# main.py
import subprocess
import sys
# 准备要传递给子脚本的参数
# 第一个参数是脚本名,后面的是传递给该脚本的参数
args = ['python', 'child_script.py', 'arg1', 'arg2']
print("Main script: about to run the child script.")
# 使用 run() 函数执行命令
# capture_output=True 会捕获子进程的标准输出和标准错误
# text=True 会以文本形式返回输出
# check=True 会在子进程返回非零退出码(即出错)时抛出异常
try:
result = subprocess.run(args, capture_output=True, text=True, check=True)
print("\nMain script: child script finished successfully.")
print("--- Child's STDOUT ---")
print(result.stdout) # 打印子脚本的输出
# 如果子脚本有错误输出(print 到 stderr),可以通过 result.stderr 查看
# print("--- Child's STDERR ---")
# print(result.stderr)
except subprocess.CalledProcessError as e:
print(f"Child script failed with error code {e.returncode}")
print(f"Error output: {e.stderr}")
print("Main script: continuing execution...")
如何运行: 在终端运行:
python main.py
优点:
- 完全隔离:子脚本在独立的进程中运行,它的内存、变量、错误不会影响主脚本。
- 可以捕获输入输出:非常适合将其他脚本或命令行工具当作“黑盒”来调用,并获取其结果。
- 可以传递命令行参数。
缺点:
- 开销大:创建一个新进程比导入模块要慢得多,资源消耗也更大。
- 通信复杂:如果需要主脚本和子脚本之间进行复杂的数据交换(不只是简单的字符串),会比在同一个进程内导入模块麻烦得多。
总结与最佳实践
| 方法 | 语法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
import |
import moduleimport module as aliasfrom module import func |
Pythonic, 清晰, 安全, 高效 | 无明显缺点 | 绝大多数情况下的首选,代码模块化、复用、构建大型应用。 |
exec() |
exec(file_content) |
动态,灵活 | 安全风险高,破坏命名空间,难调试 | 动态代码执行,脚本引擎。应尽量避免。 |
subprocess |
subprocess.run(['python', 'script.py']) |
进程隔离,可捕获I/O,可传参 | 开销大,通信复杂 | 调用独立的命令行工具、需要隔离环境、或作为“黑盒”执行外部脚本。 |
最终建议:
- 首选
import:当你需要在一个 Python 程序中使用另一个 Python 文件中的代码时,毫不犹豫地使用import,这是最正确、最安全、最符合 Python 设计哲学的方式。 - 次选
subprocess:当你需要将另一个 Python 脚本(或任何其他命令行程序)作为一个独立的、外部的工具来执行,并获取其输出时,使用subprocess。 - 避免
exec():除非你有非常特殊且明确的需求,并且完全理解其风险,否则不要使用exec()来执行整个文件。
