Python 包导入的困惑

2021-11-05 08:52:33 +08:00
 zxCoder

下载了一个 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'

这是为什么呢?

4447 次点击
所在节点    Python
39 条回复
zxCoder
2021-11-05 17:02:06 +08:00
@orzglory 我用一楼的方法改好了。。。。但是谁能告诉我这是什么原因,python 版本问题吗?

这个项目我看也没有人提出相关的 issue ,肯定是能跑的
Latin
2021-11-05 17:07:52 +08:00
Latin
2021-11-05 17:08:32 +08:00
基本上开源出来的算法模块现在都是这个套路吼
misaka19000
2021-11-05 17:26:54 +08:00
@orzglory 我就教了怎么了,你哪来的优越感?下次怼人之前麻烦先把你写的代码亮出来看看都是些什么东西
oOoOoOoOoOo
2021-11-05 20:40:41 +08:00
working_dir 决定一切
manfredexz
2021-11-05 21:05:24 +08:00
当你搞不清楚谁说的是对的时候,请查阅官方的文档
https://docs.python.org/3/tutorial/modules.html#the-module-search-path

简单来说先查内置 package 再查脚本的当前目录 再查 PYTHONPATH
ila
2021-11-05 21:28:13 +08:00
你去看 flask 等项目的目录结构,
被 import 的路径里包含了__init__.py 文件。
而且官方文档也是建议这样做。
ila
2021-11-05 21:29:25 +08:00
不要第一步就改环境变量,该设置的都在安装(软件和包)时设置好了
XIVN1987
2021-11-05 21:48:25 +08:00
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” 目录下
XIVN1987
2021-11-05 22:04:50 +08:00
```
>>> 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”执行正常。
Trim21
2021-11-05 22:32:26 +08:00
@Latin 你没注意到这几行实际上被注释掉了吗…
akaHenry
2021-11-08 12:38:20 +08:00
@zxCoder 我的解释是原因, 你按照我的改法, 添加一个 init.py 文件(补上面的下划线, v 站说这是链接). 应该不用改代码就可以跑. 原因, 我解释了哇.

from A.yyy , 这里 A 是 package 的前提是, A 同级目录, 要有 init.py 文件. 才是 Python package 目录, 否则只是普通文件夹.
akaHenry
2021-11-08 12:40:56 +08:00
@Trim21 所以这些人, 真的可爱. 贴个注释给我看.

27 楼, 跟我指出的问题. 是一致的.

这些不懂装懂的, 就不要出来误导别人.

这下面, 一排连 Python package 模块目录和 普通目录都没搞清楚的, 这基本功, 够可以.
akaHenry
2021-11-08 12:46:55 +08:00
@misaka19000 不懂装懂, 指出来. 就跳脚.

py 社区, 就剩下这种水平的出来胡说八道. 可悲.
Trim21
2021-11-08 12:48:58 +08:00
@orzglory 没有__init__.py 文件的还有可能是 python namespace package 啊...
akaHenry
2021-11-08 12:51:29 +08:00
@Trim21 lz 的这个脚本. 显然与此无关呀.
akaHenry
2021-11-08 12:55:49 +08:00
namespace package 是给 setup.py 这种安装脚本用的. 不是给日常场景滥用的.

这个特性本身, 我认为只是为了 hack 一些问题而打的补丁.
onlylovehuan
2021-11-08 13:27:35 +08:00
跑的时候命令行先跑到 XXXProject 路径下面,再执行
O5oz6z3
2021-11-08 14:00:36 +08:00
#5 和#26 楼的文档说完了。项目可能没问题如#13 #29 所说需要全局安装。
#26 docs.python.org/zh-cn/3/tutorial/modules.html#the-module-search-path
#12 docs.python.org/zh-cn/3/using/cmdline.html#cmdarg-script
#6 docs.python.org/zh-cn/3/using/cmdline.html#envvar-PYTHONPATH
#16 docs.python.org/zh-cn/3/using/cmdline.html#cmdoption-m
__init__.py 只是规范问题,加不加效果上我猜区别不大……

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/813185

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX