Jupyter Notebook中运行Python文件的四种方法详解

10 次阅读

Jupyter Notebook 不仅适合交互式编写和调试 Python 代码,也可以直接调用已经保存好的 .py 文件。根据文件内容、执行目的以及开发习惯不同,可以选择不同的运行方式。常见方法主要有四种:使用 %run 魔法命令、使用 exec() 执行文件内容、通过 subprocess 调用 Python 解释器,以及在终端中使用 python 命令运行脚本。

一、使用 %run 命令运行 Python 文件

%run 是 Jupyter Notebook 中最直接、最常用的运行 Python 文件方法,特别适合需要在 Notebook 环境中测试现有 Python 脚本的场景。

假设当前目录下存在一个 test.py 文件:

Python
运行
print("Hello Jupyter")
name = "Python"
print(name)

在 Jupyter Notebook 单元格中直接执行:

Python
运行
%run test.py

运行结果:

Hello Jupyter
Python

如果 Python 文件不在当前工作目录,可以指定完整路径或相对路径:

Python
运行
%run ./scripts/test.py

Windows 环境也可以使用:

Python
运行
%run D:/python_project/test.py

使用 %run 的一个重要特点是,脚本执行完成后,其中定义的变量、函数和类通常可以直接在当前 Notebook 环境中继续使用。例如:

Python
运行
# test.py
message = "Hello Python"

def add(a, b):
    return a + b

Notebook 中执行:

Python
运行
%run test.py

随后可以直接调用:

Python
运行
print(message)
print(add(10, 20))

输出:

Hello Python
30

因此,如果目标是“运行一个 .py 文件,并继续使用其中定义的变量和函数”,%run 通常是优先选择。

%run 传递命令行参数

如果 Python 文件需要参数,也可以直接写在文件名后面:

Python
运行
%run test.py hello 123

脚本中可以通过 sys.argv 获取参数:

Python
运行
import sys

print(sys.argv)

这种方式比较适合测试带有命令行参数的 Python 程序。

%run 指定运行目录

某些脚本依赖特定工作目录,可以使用 -i、-n 等参数控制执行行为。例如:

Python
运行
%run -i test.py

-i 表示在当前交互式命名空间中执行脚本,可以方便脚本访问 Notebook 中已经定义的变量。


二、使用 exec() 执行 Python 文件

第二种方式是使用 Python 内置的 exec() 函数读取 .py 文件内容,然后动态执行。

最简单的写法如下:

Python
运行
exec(open("test.py", encoding="utf-8").read())

如果文件路径不同,可以修改为:

Python
运行
exec(open("./scripts/test.py", encoding="utf-8").read())

这种方法本质上是先读取 Python 文件中的源代码,再将代码交给 Python 解释器执行。

例如 test.py 内容为:

Python
运行
x = 100
y = 200

print(x + y)

Notebook 中执行:

Python
运行
exec(open("test.py", encoding="utf-8").read())

输出:

300

同时,x 和 y 也会出现在当前执行环境中:

Python
运行
print(x)
print(y)

结果:

100
200

使用 exec() 时需要注意编码

如果 Python 文件包含中文内容,建议显式指定编码:

Python
运行
exec(open("test.py", encoding="utf-8").read())

这样可以降低因为系统默认编码不同而产生的 UnicodeDecodeError 风险。

exec() 更适合什么场景

exec() 灵活性较高,可以动态加载和执行字符串形式的 Python 代码。例如:

Python
运行
code = """
a = 10
b = 20
print(a + b)
"""

exec(code)

不过,如果只是为了在 Jupyter Notebook 中运行一个普通 .py 文件,通常没有必要优先使用 exec()。相比之下,%run 可读性更好,而且专门针对 Notebook 与 Python 脚本之间的交互进行了设计。

另外,不要对来源不可信的 Python 文件随意使用 exec(),因为 exec() 会直接执行其中包含的代码。


三、使用 subprocess 调用 Python 解释器

第三种方式是通过 subprocess 模块启动一个独立的 Python 进程运行 .py 文件。

示例:

Python
运行
import subprocess

result = subprocess.run(
    ["python", "test.py"],
    capture_output=True,
    text=True
)

print(result.stdout)

如果当前系统中需要明确使用 python3,可以写:

Python
运行
import subprocess

result = subprocess.run(
    ["python3", "test.py"],
    capture_output=True,
    text=True
)

print(result.stdout)

这种方式和 %run 有一个非常明显的区别:subprocess 启动的是独立进程。

例如 test.py:

Python
运行
x = 100
print(x)

Notebook 执行:

Python
运行
import subprocess

subprocess.run(["python", "test.py"])

虽然脚本会输出:

100

但脚本中的 x 并不会自动成为当前 Notebook 的变量:

Python
运行
print(x)

可能得到:

NameError: name 'x' is not defined

这是因为 Notebook 和 test.py 分别运行在不同的 Python 进程中。

获取脚本执行结果

如果需要获取 Python 文件的标准输出,可以使用:

Python
运行
import subprocess

result = subprocess.run(
    ["python", "test.py"],
    capture_output=True,
    text=True
)

print(result.stdout)

如果脚本执行失败,还可以检查返回码:

Python
运行
if result.returncode == 0:
    print("执行成功")
else:
    print("执行失败")
    print(result.stderr)

这种方式非常适合测试独立 Python 程序,尤其是脚本本身依赖命令行环境、需要独立进程或者需要模拟生产运行方式时。

指定 Python 解释器

如果电脑上安装了多个 Python 版本,直接写 python 可能调用错误的解释器。这种情况下可以直接指定解释器路径:

Python
运行
import subprocess

subprocess.run([
    r"C:Python311python.exe",
    "test.py"
])

Linux 环境可以类似这样:

Python
运行
subprocess.run([
    "/usr/bin/python3",
    "test.py"
])

这种方式对于解决 Python 环境混乱、虚拟环境与 Notebook 内核不一致等问题非常有帮助。


四、通过 Jupyter Notebook 的终端命令运行 Python 文件

Jupyter Notebook 还支持通过 ! 执行系统命令,因此可以直接调用 Python:

Python
运行
!python test.py

Linux 或 macOS 中也可以:

Python
运行
!python3 test.py

如果脚本路径包含空格,建议使用引号:

Python
运行
!python "my scripts/test.py"

这种方法实际上是在 Notebook 中调用系统 Shell 命令,使用起来非常接近在命令行窗口运行 Python 文件。

例如:

Python
运行
!python test.py

对应于操作系统终端中的:

Bash
python test.py

使用参数运行

同样可以传递参数:

Python
运行
!python test.py hello 123

如果 test.py 使用:

Python
运行
import sys

print(sys.argv)

就可以看到传入的命令行参数。

使用当前 Notebook 的 Python 环境

相比直接写:

Python
运行
!python test.py

更推荐在需要确保解释器一致时使用:

Python
运行
import sys

!{sys.executable} test.py

sys.executable 会获取当前 Notebook 内核所使用的 Python 解释器路径。

例如:

Python
运行
import sys
print(sys.executable)

可能得到:

C:Usersusernaconda3envsmyenvpython.exe

然后:

Python
运行
!{sys.executable} test.py

就能够明确使用当前 Jupyter 内核对应的 Python 环境。

这一点对于 Anaconda、venv、conda 环境尤其重要,可以避免出现“Notebook 中可以导入某个库,但运行 Python 文件时却提示找不到模块”的情况。


四种方法如何选择

四种方法都可以在 Jupyter Notebook 中运行 Python 文件,但适用场景并不完全相同。

方法是否独立进程变量是否进入Notebook是否适合传参数主要用途
%run test.py否是是Notebook中调试、测试脚本
exec()否是需要自行处理动态执行Python代码
subprocess.run()是否是独立运行Python程序
!python test.py是否是快速执行系统命令

如果只是想快速运行一个 Python 文件,优先考虑:

Python
运行
%run test.py

如果希望脚本和当前 Notebook 环境共享变量,可以使用:

Python
运行
%run test.py

或者根据特殊需求使用:

Python
运行
exec(open("test.py", encoding="utf-8").read())

如果希望以独立 Python 程序的方式运行,则更适合:

Python
运行
import subprocess

subprocess.run([sys.executable, "test.py"])

如果只是偶尔执行脚本或其他系统命令,可以使用:

Python
运行
!{sys.executable} test.py

Jupyter Notebook 中运行 Python 文件时的路径问题

实际使用过程中,最常见的问题之一并不是 Python 文件本身,而是文件路径。

可以使用下面的代码查看 Notebook 当前工作目录:

Python
运行
import os

print(os.getcwd())

如果 test.py 不在这个目录,就需要使用正确的相对路径:

Python
运行
%run ./scripts/test.py

也可以使用绝对路径:

Python
运行
%run "D:/project/scripts/test.py"

Windows 路径建议使用正斜杠:

Python
运行
%run D:/project/test.py

或者使用原始字符串:

Python
运行
path = r"D:project	est.py"

如果项目结构类似:

project/
├── notebook/
│   └── demo.ipynb
├── scripts/
│   └── test.py
└── data/
    └── data.csv

Notebook 位于 notebook 目录时,可以运行:

Python
运行
%run ../scripts/test.py

但需要注意,脚本内部使用的相对路径通常与当前工作目录有关,而不是简单地以 .py 文件所在目录作为基准。因此,复杂项目中最好明确管理工作目录和资源路径。


如何解决“找不到 Python 文件”的问题

如果执行:

Python
运行
%run test.py

出现类似:

FileNotFoundError

首先检查当前工作目录:

Python
运行
import os
print(os.getcwd())

然后查看当前目录中的文件:

Python
运行
os.listdir()

如果没有看到 test.py,说明脚本不在当前工作目录,需要调整路径。

也可以直接判断文件是否存在:

Python
运行
import os

print(os.path.exists("test.py"))

返回:

True

说明路径正确;如果返回:

False

则需要检查文件名称、目录以及路径写法。


运行 Python 文件后修改代码为什么没有立即生效

有些情况下,用户修改了 .py 文件,再次执行时发现结果似乎没有按照预期变化。

对于普通 %run 操作,重新运行:

Python
运行
%run test.py

通常会重新读取并执行脚本。

如果使用的是模块导入方式,例如:

Python
运行
import test

那么 Python 会缓存已经导入的模块。修改 test.py 后再次执行:

Python
运行
import test

不一定会重新加载文件。

这种情况下可以使用:

Python
运行
import importlib
import test

importlib.reload(test)

因此,“运行 Python 文件”和“导入 Python 模块”是两个不同概念。需要反复调试脚本时,%run 往往比单纯 import 更直观。


推荐的实际使用方式

对于数据分析、机器学习和日常 Python 开发,Jupyter Notebook 通常负责实验和验证,而 .py 文件负责保存相对完整的程序逻辑。

例如项目中有:

project/
├── analysis.ipynb
├── train.py
├── utils.py
└── data/

Notebook 中需要快速测试训练脚本时,可以使用:

Python
运行
%run train.py

如果训练脚本需要参数:

Python
运行
%run train.py --epochs 20 --batch-size 32

如果希望完全按照独立程序的形式执行:

Python
运行
import subprocess
import sys

result = subprocess.run(
    [sys.executable, "train.py", "--epochs", "20"],
    capture_output=True,
    text=True
)

print(result.stdout)

而对于只需要快速执行一次的脚本:

Python
运行
!{sys.executable} train.py

即可满足需求。


总结

Jupyter Notebook 中运行 Python 文件并不只有一种方式。%run 是最适合日常 Notebook 开发的方案,语法简单,并且能够方便地使用脚本中的变量和函数;exec() 更偏向动态执行 Python 源代码,灵活但需要注意安全性;subprocess 适合需要独立 Python 进程的场景,可以更接近真实命令行环境;!python 则适合快速调用系统命令。

如果主要目的是调试和分析 .py 文件,优先使用:

Python
运行
%run test.py

如果需要确保使用当前 Notebook 对应的 Python 环境,则可以采用:

Python
运行
import sys
!{sys.executable} test.py

掌握这四种方法后,可以根据是否需要共享变量、是否需要独立进程、是否需要传递命令行参数以及 Python 环境是否一致等条件,选择最合适的运行方案。