杰瑞科技汇

Python程序如何直接调用另一个Python文件?

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

Python程序如何直接调用另一个Python文件?-图1
(图片来源网络,侵删)

核心概念:模块与包

要理解 Python 的基本组织结构:

  • 模块:一个 .py 文件就是一个模块,模块中定义的函数、类和变量都可以被其他程序引入。
  • :一个包含 __init__.py 文件的目录,用于组织多个相关的模块。

当你调用一个 Python 文件时,你通常是在将其作为一个模块来导入。


使用 import 语句 (最常用、最推荐)

这是最标准、最 Pythonic 的方式,它会执行被导入文件(模块)中的所有顶层代码,并将其中的函数、类、变量等加载到当前命名空间中。

场景1:导入整个模块

假设你有两个文件,在同一目录下:

Python程序如何直接调用另一个Python文件?-图2
(图片来源网络,侵删)

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

输出结果:

Python程序如何直接调用另一个Python文件?-图3
(图片来源网络,侵删)
模块 my_module 已被导入  <-- 这是 my_module.py 中的 print 语句
Hello, Alice!
当前版本是: 1.0

关键点:

  • 使用 import my_module 后,必须通过 模块名.成员名 (如 my_module.greet) 来访问。
  • 一个模块只会被导入一次,即使你在 main.pyimport 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 设计的初衷,也是最安全、最清晰、最符合社区规范的方式。

分享:
扫描分享到社交APP
上一篇
下一篇