欢迎光临散文网 会员登陆 & 注册

python import坑总结

2023-02-17 16:33 作者:Robird  | 我要投稿

如果所有代码都在同一个目录,一切都简单而美好。

然而一旦源码分目录,目录内的代码需要让目录外访问,那就没有完美方案。

pf

│  m4.py

│  __init__.py

├─pa

│      m1.py

│      m2.py

│      __init__.py

└─pb

        m3.py

        __init__.py

m2引用m1

m3引用m2

m4引用m2

问题的根源在于:

    1 每次我们写import xx的时候,注意此时开头没有./../...这样的相对路径,都是相对于__main__的路径的,不是run python时的启动路径的,也不是文件自身。也就是说,从m3和m4分别作为__main__引用m2时,m2内不能简单写from m1。因为pb和pf内都没有m1。

    2 当我们写from .xx/..xx import yy时,是相对于文件自身,但是这个文件就不能直接作为__main__直接执行了。因为./..要先查找上级,然而__main__没有上级,本身就是根了。这是个必须面对的问题,直接执行的能力对于小项目,或者就是日常实验的小玩具,是很方便的。或者从toy逐步长成project是很自然的。

方案1:

    m2内写from pa.m1

    好处,m4都能引用m2。

    代价1,m2文件对pa目录的名称产生了依赖,甚至依赖于直到自己在工程中的完整层级路径,即使保持m1在m2同目录内。

    代价2,m2本身不能作为__main__直接执行了,因为sys.path包pa含但不包含pf,在pa路径下是找不到pa自己的。

    代价3,m3依然不能引用m2,因为pb内没有pa。

方案1a:

    在方案1的基础上,修正代价2,3。在m2内的最开始增加代码:

        import sys

        import os

        sys.path[0]=os.path.abspath(".")#不替代的话,append,insert也行,重名问题。

    并且,所有__main__都在pf这一级执行。本质是将import的根路径从__main__替换成了python的启动路径。

    这使得当我们在pf内执行python pa/m2.py是,sys.path中不只有pa还有pf。

    注意重名问题。

方案2:

    m2内写from .m1。

    好处,m2不需要知道m1所在的路径叫啥名了。只要m1和m2保持在同一目录就行。

    代价,m2彻底不能作为__main__执行了,根没有父也就没有兄。原直接执行功能需要挪到新文件中。

    探讨,这里如果python能像python -m一样,虚拟一个包含所有同级module的父节点就好了,这是最接近大家直观需求和其他语言简单情况的行为;以文件的视角思考,而非以项目根目录的角度思考。

方案3:

    使用namespace

    未完待续。。。


python import坑总结的评论 (共 条)

分享到微博请遵守国家法律