使用 open() 和 write()
这是最基础的方法,适用于任何Python环境。
步骤 1:创建并写入Python文件
使用 open() 函数以写入模式('w')创建一个文件,然后用 write() 方法写入字符串形式的Python代码。
示例:创建一个简单的 hello.py 文件
# 要写入的Python代码
code_to_write = """# 这是一个简单的Python脚本
print("Hello from the written file!")
name = "World"
print(f"Hello, {name}!")
# 定义一个简单的函数
def greet(who):
print(f"Greetings, {who}!")
greet("Python")
"""
# 使用 'with' 语句打开文件,它会自动处理文件的关闭
# 'w' 模式会覆盖文件如果它已存在
with open('hello.py', 'w', encoding='utf-8') as f:
f.write(code_to_write)
print("文件 'hello.py' 已成功创建。")
运行这段代码后,你的项目目录下就会出现一个 hello.py 文件,内容如上所示。
步骤 2:在Python环境中运行该文件
我们有了一个.py文件,接下来就是在当前环境中执行它,有几种方式:
使用 subprocess 模块(推荐)
这是最强大、最灵活的方法,因为它可以让你像在终端里一样运行文件,并且可以捕获输出、错误码等。
优点:
- 模拟真实的命令行执行。
- 可以控制输入/输出流。
- 可以获取进程的返回码(
exit code)。
示例:
import subprocess
import os
# 确保文件存在
if os.path.exists('hello.py'):
try:
# 使用 subprocess.run() 来执行文件
# 'python hello.py' 是要在终端执行的命令
# capture_output=True 捕获标准输出和标准错误
# text=True 将输出解码为文本
# check=True 如果进程返回非零状态码(即出错),则抛出 CalledProcessError
result = subprocess.run(['python', 'hello.py'], capture_output=True, text=True, check=True)
print("--- 执行成功 ---")
print("标准输出:")
print(result.stdout)
except subprocess.CalledProcessError as e:
print("--- 执行失败 ---")
print(f"返回码: {e.returncode}")
print("标准错误:")
print(e.stderr)
else:
print("错误: 'hello.py' 文件不存在。")
输出:
--- 执行成功 ---
标准输出:
Hello from the written file!
Hello, World!
Greetings, Python!
使用 exec() 函数(不推荐用于外部文件)
exec() 函数会动态执行一个字符串或代码文件中的Python代码。注意:这非常危险,如果执行的代码来自不可信的来源,可能会导致安全风险(例如代码注入攻击)。
优点:
- 速度极快,因为它直接在当前解释器中执行,没有创建新进程的开销。
- 可以直接访问和修改当前脚本的命名空间(变量、函数等)。
缺点:
- 安全风险高,绝对不要对用户提供的、不可信的代码使用
exec()。 - 可能会污染当前的命名空间,导致变量冲突。
示例:
import os
if os.path.exists('hello.py'):
with open('hello.py', 'r', encoding='utf-8') as f:
code_string = f.read()
print("--- 使用 exec() 执行 ---")
# 执行文件中的代码
exec(code_string)
# 你可以看到,文件中的函数 `greet` 已经被加载到了当前命名空间
# 你可以直接调用它
print("\n在当前命名空间中调用文件中的函数:")
greet("Exec function")
else:
print("错误: 'hello.py' 文件不存在。")
输出:
--- 使用 exec() 执行 ---
Hello from the written file!
Hello, World!
Greetings, Python!
在当前命名空间中调用文件中的函数:
Greetings, Exec function!
将文件作为模块导入
如果你的Python文件是一个可重用的模块(即它包含函数、类等,而不是直接执行一堆代码),最好的方法是将其作为模块导入。
步骤 1:创建模块文件
创建一个名为 my_module.py 的文件:
# my_module.py
def add(a, b):
"""这是一个加法函数"""
print(f"正在计算 {a} + {b}")
return a + b
VERSION = "1.0"
步骤 2:在另一个脚本中导入并使用
# main_script.py
import my_module
# 使用模块中的函数
result = my_module.add(10, 5)
print(f"结果是: {result}")
# 使用模块中的变量
print(f"模块版本: {my_module.VERSION}")
运行 main_script.py 的输出:
正在计算 10 + 5
结果是: 15
模块版本: 1.0
优点:
- Pythonic(符合Python风格)。
- 代码结构清晰,易于管理和重用。
- 避免了全局命名空间污染。
总结与最佳实践
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
subprocess.run() |
最通用,需要独立运行一个脚本、捕获输出、处理错误、传递参数。 | 安全、灵活、模拟真实终端环境。 | 有进程创建和通信的开销。 |
exec() |
高级/特定用途,动态生成并执行代码(在Jupyter Notebook中运行用户输入的代码片段)。 | 速度快,无额外进程开销。 | 安全风险极高,可能污染命名空间。 |
import |
模块化开发,当你的代码是可重用的库、工具集或类时。 | 结构清晰、可重用、安全、Pythonic。 | 文件必须是有效的模块,不能有顶层执行的代码(或需用 if __name__ == "__main__": 保护)。 |
如何选择?
- 如果你只是想运行一个写好的脚本,并获取其结果:使用
subprocess.run(),这是最标准、最安全的选择。 - 如果你在构建一个工具,需要动态执行用户提供的、受控的代码片段:可以考虑
exec(),但要极其小心,并做好沙箱处理。 - 如果你在构建一个应用程序,并且你写的文件是其中的一部分功能:使用
import将其作为模块导入,这是最好的软件工程实践。
重要提示:if __name__ == "__main__":
当你用 import 导入一个模块时,模块里的所有代码都会被执行,这通常不是你想要的,为了区分“作为模块被导入”和“作为脚本直接运行”,可以使用 if __name__ == "__main__":。
修改 hello.py:
# hello.py
def greet(who):
print(f"Greetings, {who}!")
# 这部分代码只有在文件被直接运行时才会执行
if __name__ == "__main__":
print("Hello from the written file!")
name = "World"
print(f"Hello, {name}!")
greet("Python")
当你用 import hello 时,print 语句不会执行,只有 greet 函数被定义,当你用 python hello.py 或 subprocess.run(['python', 'hello.py']) 运行时,if 语句内的代码才会执行,这使得文件既可以作为模块,也可以作为脚本。
