You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

直接运行脚本时包导入正常,被导入时失败的原因及解决办法

Python模块导入的场景兼容问题

场景说明

目录结构:

main_script.py
tools/
    __init__.py
    a.py
    b.py

a.py 代码

import argparse
from b import b_func

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a')
    args = parser.parse_args()
    b_func(args.a)

def a_func(x):
    return x 

if __name__ == '__main__':
    main()

直接运行python tools/a.py foo时一切正常。

main_script.py 代码

import argparse
from a import a_func

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a')
    args = parser.parse_args()
    a_func(args.a)

if __name__ == '__main__':
    main()

运行python main_script.py foo时报错:

ModuleNotFoundError: No module named 'b'

若将a.py中的导入改为from tools.b import b_func,则无法再直接运行python a.py foo。

原因分析

Python的模块搜索路径(sys.path)会根据运行方式不同而变化:

  • 直接运行a.py时:Python会把当前执行脚本所在的目录(tools/)加入sys.path,所以from b import b_func能找到同目录下的b.py。
  • 从main_script.py导入a.py时:Python会把main_script.py所在的根目录加入sys.path。此时a.py中执行from b import b_func会在根目录下找b.py,而根目录没有这个文件,所以报错。
  • 若改成from tools.b import b_func,直接运行a.py时,sys.path是tools/,根目录不在搜索路径里,找不到tools包,因此报错。

解决方案

提供两种可靠的修正方式:

方式1:动态调整sys.path(兼容直接运行和导入)

修改a.py的开头,手动将当前脚本所在目录加入模块搜索路径,确保两种场景下都能找到b.py:

import os
import sys
import argparse

# 获取当前脚本所在的绝对目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 将该目录加入sys.path的最前面,优先搜索
if current_dir not in sys.path:
    sys.path.insert(0, current_dir)

from b import b_func

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a')
    args = parser.parse_args()
    b_func(args.a)

def a_func(x):
    return x 

if __name__ == '__main__':
    main()

同时,修改main_script.py的导入语句,从tools包导入a模块:

import argparse
from tools.a import a_func  # 修改导入路径

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a')
    args = parser.parse_args()
    a_func(args.a)

if __name__ == '__main__':
    main()

方式2:使用相对导入+包模式运行

这种方式更符合Python包的规范:

  1. 修改a.py的导入为相对导入:
import argparse
from .b import b_func  # 相对导入同目录的b模块

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a')
    args = parser.parse_args()
    b_func(args.a)

def a_func(x):
    return x 

if __name__ == '__main__':
    main()
  1. 修改main_script.py的导入路径:
import argparse
from tools.a import a_func

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('a')
    args = parser.parse_args()
    a_func(args.a)

if __name__ == '__main__':
    main()
  1. 直接运行a.py时,使用包模块的方式启动(而非直接运行脚本):
python -m tools.a foo

这种方式会把根目录加入sys.path,tools作为包被识别,相对导入能正常工作,同时main_script.py的导入也不受影响。


内容的提问来源于stack exchange,提问作者teepee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 20:23:08