抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

前言

网上的资料大多数都比较乱,包括stackoverflow也是,也就产生了这篇笔记。

文件结构和可能存在的引用链条

现在有这样一个文件夹

文件夹
1
2
3
4
5
6
7
8
9
root
|____ a.py # 该文件作为演示的运行入口文件
|____ b.py
|____ c.py
|____ dir1
|____d.py
|____e.py
|____dir2
|____x.py

IMPORTANT

  • 我使用的是python3.11,该版本中不需要__init__.py也能把文件夹变成一个package
  • 如果你不能引入子文件夹,则直接在该文件夹中新建一个__init__.py,内容为空。

可能存在的引用链条有

  • a -> d -> b(引用父文件)

    python
    1
    2
    3
    4
    # a.py
    import d
    # d.py
    import b
  • a -> d -> x -> e(引用子文件后再引用其父文件)

  • a -> b -> c

  • a -> d -> x -> c

非运行入口文件和运行入口文件

IMPORTANT

一定要区分哪个是运行入口文件!

python a.py中,a.py就是运行入口文件,其他的都不是。如果你cd dir1 & python e.py,那么a.py就不是运行入口文件了,e.py才是。一般而言运行入口文件使用绝对引入。

绝对引入和相对引入

import a就是绝对引入,from . import a就是相对引入。也就是说带.的就是相对引入。

a -> d -> b(引用父文件)

python
1
2
3
4
5
# a.py
import d
# d.py
from .. import b
#正确写法 import b

如果你这么写的话一定会报错的,Attempted relative import with no known parent package,不报错你也不会来看我的博客()

这里假设a.py是运行入口文件,正确的写法是直接import b,这是因为b.pya.py同级,也就是说如果是要引入同运行入口文件同级的.py,则直接import就可以。

a -> d -> x -> e(引用子文件后再引用其父文件)

这个在d.py中就是正常的from .dir1 import x,但是需要注意的是,在x.py中需要使用from .. import e,这和上面那个引用父文件的方法不一样,所以说一定要注意哪个才是运行入口文件!!

a -> d -> x -> c

这里也出现了a.py引用同级的c.py的情况,与x.py引用e.py不同,x.py引用c.py的时候直接import a就可以。

a -> b -> c

最后这个也是同级,import a就可以。

在运行入口文件中引用其父文件

不是不可以,其实没什么必要这么做,因为如果后续要继续改的话会频繁出错,例如如果存在另一个同级或非同级的文件,此文件要引用原来的运行入口文件,那么原运行入口文件所引用的文件很可能就引用失败。

所以我看有些库,例如requests,官方的asyncio都是只有一个层级,大家都是非运行入口文件,互相引用的时候都是用相对引入。

如果你真的要在运行入口文件中引用其父文件,那么这样写

dir1/d.py
1
2
3
4
import sys
from os import path
sys.path(path.dirname(path.dirname(path.abspath(__file__))))
import a

评论