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'

这是为什么呢?

4691 次点击
所在节点    Python
39 条回复
mangoDB
2021-11-05 09:00:00 +08:00
from yyy import YY
Trim21
2021-11-05 09:02:45 +08:00
把 XXXProject 文件夹加到 python path 环境变量里
Latin
2021-11-05 09:18:43 +08:00
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)
ch2
2021-11-05 09:43:11 +08:00
需要加 path
frostming
2021-11-05 09:48:44 +08:00
misaka19000
2021-11-05 09:51:31 +08:00
要把 XXXProject 这个目录加到 PythonPATH 里面去

export PYTON_PATH=$PYTHON_PATH:/xxx/xxx/XXXProject
sudoy
2021-11-05 09:54:31 +08:00
@mangoDB `from yyy import YY` +1 不需要`A.yyy`, 因为 xxx.pyyyy.py 在同一个文件夹下面
Vegetable
2021-11-05 09:57:09 +08:00
@misaka19000 根目录自动添加的吧
misaka19000
2021-11-05 10:02:35 +08:00
@Vegetable 谁给你自动添加? Python 怎么知道哪个目录是根目录
Vegetable
2021-11-05 10:18:09 +08:00
@misaka19000 python 的 sys.path 第一位永远是""
Vegetable
2021-11-05 10:20:40 +08:00
@frostming 你这个确实准
misaka19000
2021-11-05 10:23:14 +08:00
@Vegetable 有的时候是不会在项目的根路径执行程序的
2i2Re2PLMaDnghL
2021-11-05 11:08:32 +08:00
我觉得更可能你没有安装这个项目,因为 git clone 下来的不会自动安装
如果根目录下有 setup[.]py 的话,应先运行 pip install -e . (你可能会希望做一个 venv ,以免把 A 安装到系统里去)
jaredyam
2021-11-05 11:10:39 +08:00
我的观点,未验证:
1. zzz.sh 的执行路径(在根目录)和执行方式( python A/xxx.py )没有问题
2. 问题是此时 A/xxx.py 被看作为为一个脚本文件直接执行,却使用了 from A.yyy import YY 从它外部的一个包(其实是包括自己的包,但包不包括自己不重要)导入模块 yyy ,按理来说直接 from yyy import YY 就好了,不需要考虑 A ,直接把 yyy 作为同级模块导入即可
3. 但是按照 2 的解决思路,A 的结构就显得很怪异,A 被强行看作一个包(有__init__.py ),但却又包含脚本。一般实践中,xxx.p 应该被拿出来,放在包外面,比如和 scripts/同级,然后在 zzz.sh 中 python xxx.py ,具体放哪看脚本干的事情,但放包里就是有问题
2i2Re2PLMaDnghL
2021-11-05 11:11:25 +08:00
@2i2Re2PLMaDnghL 发现排版不太好看清,
```
pip install -e .
```
最后的 dot 是必要的。
2i2Re2PLMaDnghL
2021-11-05 11:15:13 +08:00
@jaredyam 确实挺怪的,不过一般实践应该是为 A.xxx:main 设置一个 entrypoint ,或者 python -m A.xxx
xingheng
2021-11-05 14:33:57 +08:00
我认为 sys.path 都是扯犊子,我从来不那么干,除非在写加载动态化插件。Python 会把当前工作目录加入到 sys.path 里,这一点儿就够了。

直接改写 zzz.sh:
python ../A/xxx.py
akaHenry
2021-11-05 16:49:34 +08:00
@Latin sys.path.insert() 这种很脏的做法, 就不要再传播了.


Python 是通过 __init__.py 文件来区分 普通文件夹和 package 目录的.


你 XXXProject/ 目录下, 并没有__init__.py 文件, 你的脚本, 并不会认为这是 Python 项目.


很久不写 py 了. 建议你添加个 __init__.py 文件在 XXXProject/ 目录, 再试一下.


Python 的项目路径环境, 没什么复杂的.
akaHenry
2021-11-05 16:51:23 +08:00
@misaka19000 Python 社区, 都凋零成这样了吗?

一个小脚本, 都开始教他添加环境变量了?

阿西吧.
akaHenry
2021-11-05 16:54:50 +08:00
@xingheng 你的回复, 还算正常. ls 的都是什么鬼.

你的回复, 配合我上面的建议的修改. 应该就正常了.

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

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

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

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

© 2021 V2EX