python 绝对导入和相对导入

参考:
https://blog.csdn.net/huaanxiang/article/details/143687649

绝对导入:

标准库导入

假设有 a.py 这么写:

import os

这个是从标准库导入。

当前文件目录导入

如果 a.py 的同级目录下有一个 b.py,b.py 中有 class B,那么在 a.py 也可以导入:

from b import B

这个是从当前文件目录导入,因为运行 a.py,所以当前文件目录就是 a.py 所在目录,这个目录下有 b.py,所以导入成功。

如果嵌套导入,子模块中,当前文件目录也是最开始运行的文件的目录。
可以看下面的例子来理解:
目录树如下

│  a.py
│  a2.py
│
└─b
        b.py

a2.py:

class A2():
    pass

b.py:

from b.b import A2

a.py:

from b.b import A2

直接运行 python b/b.py,会失败:

ModuleNotFoundError: No module named 'a2'

但是运行 python a.py,是会成功的,原因在运行的顶层文件决定了工作目录,工作目录会影响每一个子模块的绝对导入路径。

site-packages 导入:

这个可以理解为导入 conda 子环境里 pip 安装的包。

优先级:

Python 导入模块时,会按以下顺序查找模块:
当前目录:首先,它会检查当前目录(即脚本所在目录)。
标准库目录:如果当前目录没有这个模块,Python 会继续在标准库目录中查找。
site-packages 目录:然后,它会在 site-packages(安装的第三方包)目录中查找。

相对导入:

注意,只要一个 .py 文件使用相对导入方法,你就不能直接运行这个文件,必须是把它当成子模块,在别的文件引用这个模块来调用。

而且,引用的过程中的最顶级目录,必须是一个包(也就是你运行的文件也不能在这个目录里)。

考虑下面的例子:

│  main.py
│
├─a
│      a.py
│
└─c
        c.py

main.py:

from a.a import C

a.py:

from ..c.c import C

c.py:

class C:
    pass

此时运行 python main.py,会报错:

ImportError: attempted relative import beyond top-level package>

原因是 a.py 中 .. 到了 ./ 这个目录,但这个目录不是一个包,所以寄,因此,需要把 a 和 c 再打包成一个包,放到 main.py 的同级目录下:

│  main.py
│
└─top
    ├─a
    │      a.py
    │
    └─c
            c.py

main.py 改成:

from top.a.a import C

此时可以运行。

sys.path.append 实现相对导入

相对导入了就不能直接运行文件,这么麻烦,就不是很好写脚本。

假设终端工作目录 ./ 下有两个文件夹:src1 和 src2
src2 里面的一个 .py 文件就是要从 src1 import 东西怎么办呢。

此时可以考虑把当前终端工作目录添加的系统路径里:
src2 中的某个文件

import sys
sys.path.append("./")

然后就可以绝对导入:

from src1.xxx import XXX

或者不在程序里写,运行程序钱,引入环境变量:

export PYTHONPATH=./

但这样要求你的终端工作目录是对的(即 ./ 是 src1 和 src2 的父目录),
注:也可以把 ./ 换成绝对目录,但这样迁移环境很麻烦。

很麻烦,怎么用 sys 实现相对呢?用 os 获得一下就行了:

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

init.py

我们发现上面的 import 都是 a.a ,第一个 a 是文件夹名,第二个 a 是文件名,很不方便
如果想直接 from a import XXX,并且这个 a 指的就是文件夹名,就需要 init.py

a 文件夹下建一个 init.py,然后:

from .a import XXX

这样就可以了,可以理解为 init.py 在帮这个文件夹 import。

posted @ 2024-12-20 21:21  Cold_Chair  阅读(13)  评论(0编辑  收藏  举报