杰瑞科技汇

python 调用另一个python

作为模块导入 (最推荐)

这是最常用、最 Pythonic 的方式,它将另一个脚本(.py 文件)当作一个模块来使用,可以无缝地调用其中的函数、类和变量。

适用场景

  • 你想重用另一个脚本中的代码(函数、类)。
  • 你需要将一个大型项目拆分成多个逻辑清晰的文件。

步骤

  1. 创建一个模块文件 (my_module.py),这个文件包含一些可复用的代码。

    # my_module.py
    def greet(name):
        """一个简单的问候函数"""
        return f"你好, {name}! 欢迎来到 Python 模块的世界。"
    def add(a, b):
        """一个加法函数"""
        return a + b
    # 模块级别的变量
    MODULE_VERSION = "1.0"
  2. 创建主脚本 (main.py),并导入 my_module

    # main.py
    # 1. 导入整个模块
    import my_module
    # 2. 调用模块中的函数
    message = my_module.greet("Alice")
    print(message)
    sum_result = my_module.add(10, 5)
    print(f"10 + 5 = {sum_result}")
    # 3. 访问模块中的变量
    print(f"当前模块版本是: {my_module.MODULE_VERSION}")
    # --- 其他导入方式 ---
    # 4. 只导入特定的函数/变量,使用时不需要加模块名前缀
    from my_module import greet, add
    print("\n使用 'from ... import ...' 语法:")
    print(add(100, 200))
    # 5. 给模块或函数起一个别名,方便使用或避免命名冲突
    import my_module as mm
    print("\n使用别名:")
    print(mm.greet("Bob"))
    from my_module import greet as say_hello
    print("\n使用函数别名:")
    print(say_hello("Charlie"))

如何运行: 在终端中,确保 my_module.pymain.py 在同一个目录下,然后运行主脚本:

python main.py

输出

你好, Alice! 欢迎来到 Python 模块的世界。
10 + 5 = 15
当前模块版本是: 1.0
使用 'from ... import ...' 语法:
300
使用别名:
你好, Bob! 欢迎来到 Python 模块的世界。
使用函数别名:
你好, Charlie! 欢迎来到 Python 模块的世界。

使用 subprocess 模块执行脚本

这种方式不是“导入”脚本,而是像在命令行中一样“运行”另一个脚本,它会创建一个新的、独立的 Python 进程。

适用场景

  • 你想将两个脚本完全解耦,它们之间不应该共享内存变量。
  • 你想传递命令行参数给另一个脚本。
  • 另一个脚本是一个独立的命令行工具,你只是想执行它并获取其输出。

示例

假设我们有一个脚本 script_to_run.py,它接受命令行参数并打印结果。

# script_to_run.py
import sys
if __name__ == "__main__":
    print(f"脚本 {__file__} 开始运行...")
    print(f"接收到的参数数量: {len(sys.argv)}")
    if len(sys.argv) > 1:
        for i, arg in enumerate(sys.argv):
            print(f"参数 {i}: {arg}")
    else:
        print("没有接收到额外参数。")
    print("脚本运行结束。")

我们在 main.py 中使用 subprocess 来调用它。

# main.py
import subprocess
import sys
# --- 场景1: 运行脚本,不传递参数 ---
print("--- 场景1: 不带参数运行 ---")
subprocess.run(["python", "script_to_run.py"])
print("\n" + "="*30 + "\n")
# --- 场景2: 运行脚本,并传递参数 ---
print("--- 场景2: 带参数运行 ---")
# 注意:参数需要是一个列表,每个元素都是一个独立的字符串
command = ["python", "script_to_run.py", "arg1", "arg2", "--verbose"]
subprocess.run(command)
print("\n" + "="*30 + "\n")
# --- 场景3: 获取并捕获脚本的输出 ---
print("--- 场景3: 捕获输出 ---")
result = subprocess.run(
    ["python", "script_to_run.py", "Hello from subprocess"],
    capture_output=True,  # 捕获标准输出和标准错误
    text=True,            # 将输出解码为文本
    check=True            # 如果脚本返回非零退出码,则抛出异常
)
print("脚本执行成功,返回码:", result.returncode)
print("捕获到的标准输出:")
print(result.stdout)

如何运行

python main.py

输出

--- 场景1: 不带参数运行 ---
脚本 script_to_run.py 开始运行...
接收到的参数数量: 1
参数 0: script_to_run.py
没有接收到额外参数。
脚本运行结束。
==============================
--- 场景2: 带参数运行 ---
脚本 script_to_run.py 开始运行...
接收到的参数数量: 4
参数 0: script_to_run.py
参数 1: arg1
参数 2: arg2
参数 3: --verbose
脚本运行结束。
==============================
--- 场景3: 捕获输出 ---
脚本 script_to_run.py 开始运行...
接收到的参数数量: 2
参数 0: script_to_run.py
参数 1: Hello from subprocess
脚本运行结束。
脚本执行成功,返回码: 0
捕获到的标准输出:
脚本 script_to_run.py 开始运行...
接收到的参数数量: 2
参数 0: script_to_run.py
参数 1: Hello from subprocess
没有接收到额外参数。
脚本运行结束。

使用 exec() 动态执行代码

exec() 函数会动态地执行一个字符串形式的 Python 代码,它会在当前命名空间中执行,这意味着它会修改主脚本的变量和函数。

⚠️ 警告exec() 可能存在安全风险,如果执行的代码来自不可信的来源(如用户输入),可能会导致代码注入攻击,请谨慎使用。

适用场景

  • 动态加载和执行插件或配置中定义的代码。
  • 在一个受控的环境中快速运行一段代码字符串。

示例

# main.py
import my_module # 使用方式一中的模块
# --- 场景1: 执行简单的代码字符串 ---
code_string = "print('这是通过 exec() 动态执行的代码')"
print("--- 场景1 ---")
exec(code_string)
# --- 场景2: 执行一个函数定义并调用它 ---
code_function = """
def dynamic_function(x, y):
    return x * y
"""
print("\n--- 场景2 ---")
exec(code_function)
# 注意:exec() 定义的函数在当前命名空间中可用
print(f"动态函数的结果: {dynamic_function(7, 8)}")
# --- 场景3: 在指定的命名空间中执行 ---
print("\n--- 场景3 ---")
local_namespace = {}
exec("a = 100", local_namespace)
print(f"局部命名空间中的变量 a: {local_namespace['a']}")
print(f"主脚本中的变量 a: {locals().get('a', 'a 不在主命名空间中')}") # 主脚本中没有 a
# --- 场景4: 执行另一个文件中的所有代码 ---
print("\n--- 场景4 ---")
with open("my_module.py", "r", encoding="utf-8") as f:
    module_code = f.read()
exec(module_code)
# 因为是在当前命名空间执行,所以可以直接使用 my_module.py 中定义的函数
print(f"直接调用通过 exec() 加载的 greet 函数: {greet('David')}")

如何运行

python main.py

输出

--- 场景1 ---
这是通过 exec() 动态执行的代码
--- 场景2 ---
动态函数的结果: 56
--- 场景3 ---
局部命名空间中的变量 a: 100
主脚本中的变量 a: a 不在主命名空间中
--- 场景4 ---
直接调用通过 exec() 加载的 greet 函数: 你好, David! 欢迎来到 Python 模块的世界。

总结与对比

方式 优点 缺点 适用场景
作为模块导入 首选,代码清晰、可复用、共享变量、易于调试。 耦合度相对较高,共享内存。 绝大多数情况,构建大型应用或库时。
subprocess 完全解耦,可以传递命令行参数,获取脚本输出,不共享内存。 进程开销大,通信复杂(需通过文件/网络/管道),调试稍难。 需要独立执行、传递参数、或调用现成的命令行工具时。
exec() 高度动态,可以在运行时加载和执行代码。 有安全风险,难以调试,可读性差,污染当前命名空间。 动态加载插件、执行配置代码等高级、受控场景。

简单来说

  • 想用另一个脚本的函数和变量?用 import
  • 想像一个外部命令一样运行另一个脚本?用 subprocess
  • 想在运行时把一段代码字符串变成可执行的代码?用 exec() (但要非常小心)。
分享:
扫描分享到社交APP
上一篇
下一篇