概述
关于Python import,基本上是个写Python的人都遇到过(除非你从来不拆分项目的目录结构)。这个问题在StackOverflow上被讨论了七八年,但其实早就有人提出过,只要模块搜索路径里包含项目根目录,这个愚蠢的问题就没了,但从来没有人正面回答过这个问题。
结果就是,万恶的import机制仍然在祸害着每一个人。
Python的import机制坑在哪?
假设项目目录是这样子的——
import_test
|_______ modules
| |____ __init__.py
| |____ a.py
| |____ b.py
|_______ tests
| |____ __init__.py
| |____ test_a.py
| |____ test_b.py
|_______ app.py
app.py假设是你的主程序,从这里运行的时候,import是不太容易出问题的,绝对路径也好相对路径也好。坑在tests这个目录,把测试脚本放到一个目录里这本身没问题,但是,如果你在tests下直接运行这些测试脚本,你就会踩坑。
比如,test_a.py从modules里导入了a,如下所示——
from modules import a
a = a.a1()
if a > 50:
print(a)
else:
print(100-a)
当你运行的时候,你会发现Python找不到modules在哪 ,这是自然的,因为模块搜索路径里没有包含上级目录,所以会报错ModuleNotFoundError: No module named 'modules'
import_test> python tests/test_a.py
Traceback (most recent call last):
File "tests/test_a.py", line 1, in
from modules import a
ModuleNotFoundError: No module named 'modules'
import_test>
有人说-m这个参数有效,我试过,仍然是要退回到import_test这个目录,而且要注意,不能加.py,因为此时你运行的是一个模块,如下所示——
import_test> python -m tests.test_a
100
import_test>
Pycharm的优化可能会让你更懵逼
其次,如果你用pycharm,你可能会直到上线的那天你才发现这个问题,因为pycharm非常人性化,它自动帮你把项目路径添加好了,所以在pycharm里,你是可以直接在tests下 执行test_a.py的 ,不会有任何问题。差别很容易找到,在代码最前面加上这么两行,然后分别在pycharm和其它IDE,比如vscode里执行——
import sys
print(sys.path)
你会发现pycharm里打出来的路径是更多的,它把项目根目录加进去了。如果你在不知情的情况下继续开发下去,并且你把需要直接执行的代码,放在了类似于tests这样的目录下面,而不是import_test这个根目录下,等你上线代码那天,你就有的哭了,你会看到各种导入失败的错误,而你平时用pycharm却毫无感觉……
也许这才是真正科学的做法——把测试case写成模块,而不是脚本
我因为最初用的vscode,在import这个问题上纠结了无数次……然而python的import就是这么反人类,我又不想把测试脚本全都扔到最外面,后来我发现很多项目是把测试的case写在tests目录下,然后在外面留一个入口脚本去导入这些测试case,说白了,测试case本身也变成了一个模块,测试目录变成了一个包。
参考
最后贴两篇有用的参考,第二篇是一位台湾老师写的
我摘出其中最关键的解释
# 標準的 explicit relative import 寫法
from .sample_module import sample_func
1. 包含相對路徑的檔案不能直接執行,只能作為 module 被引用,所以失敗
2. 成功印出 Hello!
相对引用是有限制的,比如tests目录下的模块是没办法通过相对引用,直接引用到modules下面去的
以我们的例子来看
from .a import a1
a = a1()
if a > 50:
print(a)
else:
print(100-a)
这个运行的结果将会是一个错误
import_test> python -m tests.test_a
Traceback (most recent call last):
……
ModuleNotFoundError: No module named 'tests.a'
import_test>
所以,我个人跨包导入的时候,都是用的绝对导入
# 標準的 absolute import 寫法
from sample_package.sample_module import sample_func
1. 如果此層目錄位置不在 python path 中,就會失敗
2. 成功印出 Hello!
也就是
from modules import a
a = a.a1()
if a > 50:
print(a)
else:
print(100-a)
小结
贴一个stackoverflow的连接,在这个连接里,被采纳的回答在7年后更新了答案,所以你就知道这个问题真的是个老问题了……
一个更加广为人知的做法是sys.path.append,但就像很多在stackoverflow上提问的人说的那样,我个人一点也不喜欢这种做法,也许只是用在测试脚本里没有问题,但它看上去更奇怪
另外,这个链接里也有一段有意思的内容——
换言之,Python的开发团队是知道这个问题也讨论过的,所以,真傲慢。
The only use case?
最后
以上就是单薄钢铁侠为你收集整理的python import什么意思_[Python] 也整理一下万恶的Python import机制的全部内容,希望文章能够帮你解决python import什么意思_[Python] 也整理一下万恶的Python import机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复