Python基础 - 本地模块的绝对导入/引用

本文探讨Python中的绝对导入,推荐使用此方法以避免错误。文章介绍了项目入口文件的重要性,它使得项目根目录被加入到sys.path中。通过四个示例详细解析了如何在不同层级和情况下进行绝对导入,包括同级、子模块和跨文件夹的导入,并分析了不正确导入导致的错误及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 项目入口文件

 2. 绝对导入


Python本地模块的引入是比较简单的,包括绝对引用和相对引用(相对引用的博客参考下一篇Python基础 - 本地模块的相对导入/引用),个人比较推荐使用绝对引用,会避免掉很多错误,本篇文章主要介绍绝对导入。

1. 项目入口文件

项目入口文件一般要放在项目根目录下,如下图1红框main.py所示,即为项目入口文件。如果运行main.py,系统会自动把入口文件所在的根目录,加入到sys.path里。这样在以引用方式导入包时,会逐一查找sys.path中的路径,第一个即为项目根目录,如下图2所示,其中sys.path的路径包括:[项目根目录。python的压缩包路径。python自带的一些库如os, json等。so库文件。使用pip/conda安装时的第三方库]

 2. 绝对导入

绝对导入是比较简单的,也比较推荐大家采用这种方式。首先根据上图画出当前的文件树,如下:

Import_Test
  |--dir1
      |--d11.py
      |--d12.py        
  |--dir2
      |--d21.py
      |--d22.py
  |--test.py     

首先我们明确一点的是,如果运行哪个文件,该文件所在的父目录就会被加载到sys.path中,在绝对导入模块时就以这个父目录为依据来查找文件夹/文件

 示例1:引入入口文件的同级目录文件

# test.py ----------------------------
from dir1.d11 import d11_f

def test_f():
    print("test")

if __name__ == '__main__':
    test_f()
    d11_f()

# dir1/d11.py ------------------------
def d11_f():
  print("d11_f")

# 运行结果如下:
(base) @118:~/Wmq/Import_Test$ python test.py
test
d11_f

从层级上看,test.py在根目录下,所以在运行时,test.py的父目录/Wmq/Import_Test被加载到sys.path中,所以引用dir1下的d11模块时,直接引用dir1,因为该目录在/Wmq/Import_Test下。

示例2:test.py没变,引入的子模块dir1.d11同时引入同级模块dir1.d12

# test.py ----------------------------
from dir1.d11 import d11_f

def test_f():
    print("test")

if __name__ == '__main__':
    test_f()
    d11_f()

# dir1/d11.py ------------------------
from dir1.d12 import d12_f

def d11_f():  
  print("d11_f")
  d12_f()

# dir1/d12.py ------------------------
def d12_f():  
  print("d12_f")

# 运行结果如下:
(base)@118:~/Wmq/Import_Test$ python test.py
test
d11_f
d12_f

同级模块的引入是比较好理解的,根据示例1,test.py在运行时,其父目录/Wmq/Import_Test被加载到sys.path中,所以无论怎么调用d12_f,都要在/Wmq/Import_Test的基础上引入,而dir1就在盖目录下,所以就是dir1.d12。

示例3:test.py没变,引入的子模块dir1.d11同时引入跨文件夹模块dir2.d21

# dir1/d11.py ------------------------
from dir2.d21 import d21_f
def d11_f():
  print("d11_f")
  d21_f()

# dir2/d21.py ------------------------
def d21_f():
  print("d21_f")

# 运行结果如下:
(base)@118:~/Wmq/Import_Test$ python test.py
test
d11_f
d21_f

从示例不难发现,在dir1文件下的d11.py中,是如何跳跃文件夹引入dir2文件下的d21.py呢?是直接导入dir2文件夹。为什么这样不报错,原因也在示例1/2中有解释,test的运行加载了父目录/Import_Test,而dir2就在父目录下,所以直接引入dir2即可。

示例4:如果不运行test.py了,只运行dir1/d11.py, 其他任何引用不变,结果如下:

# dir1/d11.py -------------------
from dir2.d21 import d21_f

def d11_f():
  print("d11_f")
  d21_f()

if __name__ == '__main__':
  d11_f()

# 运行结果报错,如下:
(base) zhangyujun@118:~/Wmq/Import_Test/dir1$ python d11.py
Traceback (most recent call last):
  File "d11.py", line 1, in <module>
    from dir2.d21 import d21_f
ModuleNotFoundError: No module named 'dir2'

运行报错了,这其实在情理之中。因为我们前面说过,如果运行哪个文件,该文件所在的父目录就会被加载到sys.path中,在绝对导入模块时就以这个父目录为依据来查找文件夹/文件。那当我们运行d11.py时,d11.py的父目录也就是dir1被加载到sys.path中,然后顺着dir1往下找,肯定找不到dir2的,所以报错。我们验证下sys.path看一下是不是dir1被加载进去了,如下:

# dir1/d11.py -------------------
import sys
print(sys.path)

from dir2.d21 import d21_f
def d11_f():
  print("d11_f")
  d21_f()

if __name__ == '__main__':
  d11_f()

# 运行结果:
(base) zhangyujun@118:~/Wmq/Import_Test/dir1$ python d11.py
['/home/zhangyujun/Wmq/Import_Test/dir1', 
'/home/zhangyujun/anaconda3/lib/python38.zip', 
'/home/zhangyujun/anaconda3/lib/python3.8', 
'/home/zhangyujun/anaconda3/lib/python3.8/lib-dynload',
'/home/zhangyujun/anaconda3/lib/python3.8/site-packages']

Traceback (most recent call last):
  File "d11.py", line 3, in <module>
    from dir2.d21 import d21_f
ModuleNotFoundError: No module named 'dir2'

确实,sys.path中的第一个是dir1目录,自然找不到dir2目录,那怎么解决这种问题呢?我们可以在sys.path里添加上根目录,运行结果即可正常,如下:

# dir1/d11.py -------------------
import sys
sys.path.append("/home/zhangyujun/Wmq/Import_Test")

from dir2.d21 import d21_f
def d11_f():  
  print("d11_f")
  d21_f()
  
if __name__ == '__main__':  
  d11_f()

# 运行结果:
(base)@118:~/Wmq/Import_Test/dir1$ python d11.py
d11_f
d21_f
C:\Users\29386\.conda\envs\grounded_sam\python.exe -X pycache_prefix=C:\Users\29386\AppData\Local\JetBrains\PyCharmCE2025.1\cpython-cache "D:/pycharm/PyCharm Community Edition 2025.1.3.1/plugins/python-ce/helpers/pydev/pydevd.py" --multiprocess --qt-support=auto --client 127.0.0.1 --port 55957 --file C:\Users\29386\segment-anything\Grounded-Segment-Anything\grounded_sam_demo.py --config GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py --grounded_checkpoint weights/groundingdino_swint_ogc.pth --sam_checkpoint weights/sam_vit_h_4b8939.pth --input_image assets/demo1.jpg --output_dir outputs 已连接到 pydev 调试器(内部版本号 251.26927.90)C:\Users\29386\.conda\envs\grounded_sam\lib\site-packages\timm\models\layers\__init__.py:48: FutureWarning: Importing from timm.models.layers is deprecated, please import via timm.layers warnings.warn(f"Importing from {__name__} is deprecated, please import via timm.layers", FutureWarning) Traceback (most recent call last): File "D:/pycharm/PyCharm Community Edition 2025.1.3.1/plugins/python-ce/helpers/pydev/pydevd.py", line 1570, in _exec pydev_imports.execfile(file, globals, locals) # execute the script File "D:\pycharm\PyCharm Community Edition 2025.1.3.1\plugins\python-ce\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile exec(compile(contents+"\n", file, 'exec'), glob, loc) File "C:\Users\29386\segment-anything\Grounded-Segment-Anything\grounded_sam_demo.py", line 22, in <module> from segment_anything import ( ImportError: cannot import name 'sam_hq_model_registry' from 'segment_anything' (C:\Users\29386\segment-anything\segment_anything\__init__.py) python-BaseException Backend tkagg is interactive backend. Turning interactive mode on. 进程已结束,退出代码为 -1073741510 (0xC000013A: interrupted by Ctrl+C)
最新发布
07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值