杰瑞科技汇

Python如何调用另一个Python脚本?

导入模块(最常用、最推荐)

这是 Python 的核心机制,当你把一个脚本当作一个“模块”来导入时,你可以直接使用它定义的函数、类和变量。

Python如何调用另一个Python脚本?-图1
(图片来源网络,侵删)

适用场景:

  • 你想复用另一个脚本中的代码(函数、类)。
  • 你想在主程序中执行另一个脚本的一部分逻辑。
  • 两个脚本需要共享数据。

步骤:

  1. 创建一个可被导入的脚本(my_module.py 这个脚本应该包含一些可重用的代码。

    # my_module.py
    def greet(name):
        """一个简单的问候函数"""
        print(f"Hello, {name}! Welcome to the module.")
    def add(a, b):
        """一个加法函数"""
        return a + b
    # 如果这个脚本被直接运行(而不是被导入),下面的代码会执行
    if __name__ == "__main__":
        print("This block runs only when my_module.py is executed directly.")
        greet("Direct Runner")
        print(f"5 + 3 = {add(5, 3)}")

    关键点: if __name__ == "__main__": 是一个非常重要的 Python 约定。

    Python如何调用另一个Python脚本?-图2
    (图片来源网络,侵删)
    • 当你直接运行 python my_module.py 时,__name__ 的值是 "__main__"if 里面的代码会执行。
    • 当你从另一个脚本 import my_module 时,__name__ 的值是模块名 "my_module"if 里面的代码不会执行,这使得你的模块既可以作为脚本独立运行,也可以作为模块被导入复用。
  2. 在主脚本中调用它(main_script.py

    # main_script.py
    # 导入整个模块
    import my_module
    # 调用模块中的函数
    my_module.greet("Alice")
    # 调用另一个函数
    sum_result = my_module.add(10, 25)
    print(f"The sum is: {sum_result}")
    # 只导入特定的函数,这样可以直接使用函数名,无需模块名前缀
    from my_module import greet, add
    greet("Bob")
    print(f"Another sum: {add(100, 200)}")
    # 导入整个模块并给它一个别名
    import my_module as mm
    mm.greet("Charlie")

运行 main_script.py 的输出:

Hello, Alice! Welcome to the module.
The sum is: 35
Hello, Bob! Welcome to the module.
Another sum: 300
Hello, Charlie! Welcome to the module.

注意,my_module.pyif __name__ == "__main__": 的代码没有被执行,因为它是被导入的。


使用 subprocess 模块(作为独立进程运行)

如果你想完全独立地运行另一个 Python 脚本,就像在命令行中输入命令一样,并且需要捕获它的输出或传递参数,subprocess 是最佳选择。

Python如何调用另一个Python脚本?-图3
(图片来源网络,侵删)

适用场景:

  • 你想将另一个脚本作为一个完全独立的“黑盒”任务来执行。
  • 你需要向被调用的脚本传递命令行参数。
  • 你需要获取被调用脚本的输出结果(标准输出、标准错误)。
  • 被调用的脚本可能会执行很长时间,你不希望阻塞主程序。

示例:

  1. 创建一个可被命令行调用的脚本(script_to_run.py 这个脚本可以接受命令行参数。

    # script_to_run.py
    import sys
    import time
    print(f"Script started. Arguments received: {sys.argv}")
    if len(sys.argv) > 1:
        name = sys.argv[1]
        print(f"Processing for {name}...")
        time.sleep(2) # 模拟一个耗时操作
        print(f"Done processing for {name}.")
    else:
        print("No arguments provided.")
    print("Script finished.")
  2. 在主脚本中使用 subprocess 调用它

    # main_script.py
    import subprocess
    import sys
    # --- 场景1: 运行一个不带参数的脚本 ---
    print("--- Running script without arguments ---")
    try:
        # subprocess.run() 会执行命令并等待它完成
        result = subprocess.run(
            [sys.executable, "script_to_run.py"], # 使用 sys.executable 来确保使用当前 Python 解释器
            capture_output=True, # 捕获标准输出和标准错误
            text=True,           # 将输出解码为文本
            check=True           # 如果脚本返回非零退出码(表示错误),则抛出异常
        )
        print("Script executed successfully!")
        print("STDOUT:", result.stdout)
        print("STDERR:", result.stderr)
    except subprocess.CalledProcessError as e:
        print(f"Script failed with error code {e.returncode}")
        print("STDOUT:", e.stdout)
        print("STDERR:", e.stderr)
    print("\n" + "="*40 + "\n")
    # --- 场景2: 运行一个带参数的脚本 ---
    print("--- Running script with arguments ---")
    try:
        # 使用列表形式传递命令和参数
        result = subprocess.run(
            [sys.executable, "script_to_run.py", "DataProcessor"],
            capture_output=True,
            text=True,
            check=True
        )
        print("Script with args executed successfully!")
        print("STDOUT:", result.stdout)
    except subprocess.CalledProcessError as e:
        print(f"Script with args failed.")
        print("STDOUT:", e.stdout)
        print("STDERR:", e.stderr)
    print("\n" + "="*40 + "\n")
    # --- 场景3: 实时打印输出 ---
    print("--- Running script and printing output in real-time ---")
    # 使用 Popen 可以更好地控制子进程
    process = subprocess.Popen(
        [sys.executable, "script_to_run.py", "RealTimeUser"],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )
    # 实时读取并打印输出
    for line in iter(process.stdout.readline, ''):
        print(line, end='')
    # 等待进程结束并检查返回码
    process.wait()
    if process.returncode != 0:
        print(f"\nProcess failed with return code {process.returncode}")
        # 读取并打印错误输出
        for line in iter(process.stderr.readline, ''):
            print(line, end='')
    else:
        print("\nProcess completed successfully.")

运行 main_script.py 的输出:

--- Running script without arguments ---
Script executed successfully!
STDOUT:
Script started. Arguments received: ['script_to_run.py']
No arguments provided.
Script finished.
STDERR:
========================================
--- Running script with arguments ---
Script with args executed successfully!
STDOUT:
Script started. Arguments received: ['script_to_run.py', 'DataProcessor']
Processing for DataProcessor...
Done processing for DataProcessor.
Script finished.
========================================
--- Running script and printing output in real-time ---
Script started. Arguments received: ['script_to_run.py', 'RealTimeUser']
Processing for RealTimeUser...
Done processing for RealTimeUser.
Script finished.
Process completed successfully.

动态导入(高级用法)

有时你只有在运行时才知道要导入哪个模块,这时可以使用 importlib

适用场景:

  • 插件系统。
  • 根据配置文件动态加载不同的功能模块。

示例:

# main_script.py
import importlib
module_name = "my_module" # 这个名字可以来自配置文件或用户输入
try:
    # 动态导入模块
    my_module = importlib.import_module(module_name)
    # 现在可以像正常导入一样使用它
    my_module.greet("Dynamic User")
    # 你甚至可以动态调用函数
    func_name = "add"
    if hasattr(my_module, func_name):
        func_to_call = getattr(my_module, func_name)
        result = func_to_call(7, 8)
        print(f"Dynamically called {func_name}(7, 8) = {result}")
except ImportError:
    print(f"Error: Module '{module_name}' not found.")

总结与选择

方法 优点 缺点 适用场景
import 模块 最常用、最 Pythonic,共享内存,代码复用性强,性能高。 被导入的代码会在导入时执行,共享全局命名空间,可能导致副作用。 绝大多数情况,当你想复用代码,逻辑紧密耦合时。
subprocess 完全隔离,可以将脚本视为独立的命令行工具,易于传递参数和捕获I/O。 开销大,创建新进程,通信慢(通过文件描述符/管道),不适合高频调用。 当需要独立执行、并行任务、或处理外部命令式脚本时。
importlib 高度灵活,实现插件化架构。 代码可读性稍差,增加了运行时复杂性。 需要根据运行时条件动态加载模块的插件系统或高级框架。

给你的建议:

  • 首选 import:如果你的两个脚本需要共享数据和逻辑,或者你想复用其中的函数和类,直接 import 它,这是 Python 的标准做法。
  • 次选 subprocess:如果你只是想“运行”另一个脚本,不关心它的内部实现,或者需要把它当作一个独立的任务来处理(比如定时任务、并行处理),并且需要传递命令行参数,那么使用 subprocess
  • 谨慎使用 importlib:除非你明确需要一个动态的插件系统,否则一般不需要用到它。
分享:
扫描分享到社交APP
上一篇
下一篇