Python 包导入的困惑
下载了一个 python 项目,目录是这样子的
XXXProject
- A
- __init__.py
- xxx.py
- yyy.py
- ...
- scripts
- zzz.sh
xxx.py 的内容是
from A.yyy import YY
if name == "__main__":
# .....
yyy.py 的内容是
class YYY():
# .....
zzz.sh 的内容是
python A/xxx.py
然后我就按照 README 所说,在项目根目录下执行 sh scripts/zzz.sh,结果报错了,错误是
ModuleNotFoundError: No module named 'A'
这是为什么呢?
按大家的说法....这就是这个项目的README本身写错了?
from yyy import YY
把 XXXProject 文件夹加到 python path 环境变量里
from future import absolute_import
from future import division
from future import print_function
import os.path as osp
import sys
def add_path(path):
if path not in sys.path:
sys.path.insert(0, path)
this_dir = osp.dirname(__file__)
lib_path = osp.join(this_dir, '..', 'lib')
add_path(lib_path)
需要加 path
精准命中
frostming.com/2019/03-13/where-do-your-packages-go/#%E8%84%9A%E6%9C%AC%E8%BF%90%E8%A1%8C%E6%96%B9%E5%BC%8F%E5%AF%B9%E6%90%9C%E7%B4%A2%E8%B7%AF%E5%BE%84%E7%9A%84%E5%BD%B1%E5%93%8D
要把 XXXProject 这个目录加到 PythonPATH 里面去
export PYTON_PATH=$PYTHON_PATH:/xxx/xxx/XXXProject
from yyy import YY
+1 不需要A.yyy
, 因为 xxx.py 和 yyy.py 在同一个文件夹下面
根目录自动添加的吧
谁给你自动添加? Python 怎么知道哪个目录是根目录
python 的 sys.path 第一位永远是""
你这个确实准
有的时候是不会在项目的根路径执行程序的
我觉得更可能你没有安装这个项目,因为 git clone 下来的不会自动安装
如果根目录下有 setup[.]py 的话,应先运行 pip install -e . (你可能会希望做一个 venv ,以免把 A 安装到系统里去)
我的观点,未验证:
- zzz.sh 的执行路径(在根目录)和执行方式( python A/xxx.py )没有问题
- 问题是此时 A/xxx.py 被看作为为一个脚本文件直接执行,却使用了 from A.yyy import YY 从它外部的一个包(其实是包括自己的包,但包不包括自己不重要)导入模块 yyy ,按理来说直接 from yyy import YY 就好了,不需要考虑 A ,直接把 yyy 作为同级模块导入即可
但是按照 2 的解决思路,A 的结构就显得很怪异,A 被强行看作一个包(有__init__.py ),但却又包含脚本。一般实践中,xxx.p 应该被拿出来,放在包外面,比如和 scripts/同级,然后在 zzz.sh 中 python xxx.py ,具体放哪看脚本干的事情,但放包里就是有问题
发现排版不太好看清,
pip install -e .
最后的 dot 是必要的。
确实挺怪的,不过一般实践应该是为 A.xxx:main 设置一个 entrypoint ,或者 python -m A.xxx
我认为 sys.path 都是扯犊子,我从来不那么干,除非在写加载动态化插件。Python 会把当前工作目录加入到 sys.path 里,这一点儿就够了。
直接改写 zzz.sh:
python ../A/xxx.py
sys.path.insert() 这种很脏的做法, 就不要再传播了.
Python 是通过 __init__.py 文件来区分 普通文件夹和 package 目录的.
你 XXXProject/ 目录下, 并没有__init__.py 文件, 你的脚本, 并不会认为这是 Python 项目.
很久不写 py 了. 建议你添加个 __init__.py 文件在 XXXProject/ 目录, 再试一下.
Python 的项目路径环境, 没什么复杂的.
Python 社区, 都凋零成这样了吗?
一个小脚本, 都开始教他添加环境变量了?
阿西吧.
你的回复, 还算正常. ls 的都是什么鬼.
你的回复, 配合我上面的建议的修改. 应该就正常了.
我用一楼的方法改好了。。。。但是谁能告诉我这是什么原因,python 版本问题吗?
这个项目我看也没有人提出相关的 issue ,肯定是能跑的
脏做法在顶流怎么解释
github.com/microsoft/scenepic/blob/eed95135ce5ea9705d1203102d4e53d1c8ea6046/docs/source/conf.py
基本上开源出来的算法模块现在都是这个套路吼
我就教了怎么了,你哪来的优越感?下次怼人之前麻烦先把你写的代码亮出来看看都是些什么东西
working_dir 决定一切
当你搞不清楚谁说的是对的时候,请查阅官方的文档
docs.python.org/3/tutorial/modules.html#the-module-search-path
简单来说先查内置 package 再查脚本的当前目录 再查 PYTHONPATH
你去看 flask 等项目的目录结构,
被 import 的路径里包含了__init__.py 文件。
而且官方文档也是建议这样做。
不要第一步就改环境变量,该设置的都在安装(软件和包)时设置好了
PEP 328: all import statements be absolute by default (searching sys.path only) with special syntax (leading dots) for accessing package-relative imports.
“from A.yyy import YY” 显然是个绝对导入,所以 python 肯定是在 sys.path 中的路径中查找 A 。。那程序要想执行只有两种方法:
1 、把 XXXProject 的路径加入 sys.path
2 、把 A 安装到现有的 sys.path 中去,比如 “lib/site-packages” 目录下
>>> import sys
>>> for x in sys.path: print(repr(x).replace(r'\\', '/'))
''
'C:/Python36/python36.zip'
'C:/Python36/DLLs'
'C:/Python36/lib'
'C:/Python36'
'C:/Python36/lib/site-packages'
当前目录确实在 sys.path 中,但当前目录指的是被 python.exe 直接执行的那个 xxx.py 所在的目录,所以 XXXProject/A 的路径在 sys.path 中,但 XXXProject 不在 sys.path 中。
所以题主的“from A.yyy import YY”执行出错,而一楼的“from yyy import YY”执行正常。
你没注意到这几行实际上被注释掉了吗…
工作 20 多年了,这 20 来年看到了很多公司系统架构,也看到了很多问题,在跟这些公司进行交流和讨论的时候,包括进行实施和方案比较的时候,都有很多各种方案的比较和妥协,因为相…
因为 Legal reasons ,Vanced 停更,主页下载链接也没了,已安装的还能用,就是不知道能用到哪天。 www.theverge.com/2022/3/13/22…
一直用 golang ,一直有人吐槽 golang 错误处理很繁琐,一开始觉得还好,直到遇见了 rust 。不得不说 rust 错误处理真的很优雅。写了一段时间 rust 反过…