0. 前言
导入的实质是什么? 以下是我从简书收到的一篇文章(https://www.jianshu.com/p/a1e91cc53b07), 我截了一个片段:
python中,每个py文件被称之为模块,每个具有__init__.py文件的目录被称为包.只要模
块或者包所在的目录在sys.path中,就可以使用import 模块或import 包来使用.可以通过以下方式查看导入路径.
>>> print(sys.path)
['D:\\PyCharm\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pydev', 'D:\\PyCharm\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\PyCharm\\PyCharm 2020.1.1\\plugins\\python\\helpers\\third_party\\thriftpy', 'D:\\PyCharm\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pydev', 'F:\\代码\\flask_test_venv\\Scripts\\python37.zip', 'd:\\anaconda\\DLLs', 'd:\\anaconda\\lib', 'd:\\anaconda', 'F:\\代码\\flask_test_venv', 'F:\\代码\\flask_test_venv\\lib\\site-packages', 'D:\\PyCharm\\PyCharm 2020.1.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend', 'F:\\代码\\flask_test_venv', 'F:/代码/flask_test_venv']
1. 问题原因之一: 从现有包中导入不存在名称
例如:
>>> from flask import notexist
Traceback (most recent call last):
File "", line 1, in <module>
ImportError: cannot import name 'notexist' from 'flask' (F:\代码\flask_test_venv\lib\site-packages\flask\__init__.py)
由于"notexist"这个名称根本不存在于包flask
中, 所以会导致导入失败.
解决方式: 检查命名.
2. 问题原因之二: 自定义包覆盖python原有包
例如: 我们自己定义了一个包叫做http
, 而我们的工程中用到了requests
这个包, 那我们import requests
可能会出现这个错误, 因为requests
模块会试图从http
包中导入相关名称, 但是这个http
包使我们自己定义的, 其中不包含requests
引用的(官方http
包中的)名称.
https://blog.csdn.net/u012206617/article/details/101292699
有很多相同问题博客, 上边就是一个例子.
应该是学习七月老师的python flask实战课程遇到的问题.
解决方式: 将自定义包改名, 比如myhttp
.
3. 问题原因之三: 循环引用导致导入失败
这个问题是最棘手的, 问题三的解决方式有很多, 网络上也都给出了答案.比如可以采取:
以上两种解决方案博客https://www.jianshu.com/p/a1e91cc53b07中都描述了问题和解决方案, 或者网络上搜索"循环引用"也能搜到很多类似解决方案.
但是对于最最根本的解决方案都是一句带过:重新设计代码结构.是的, 重新设计代码结构可以解决问题, 重新设计的思路是什么样的? 俗话说授人以鱼不如授人以渔, 下面我给大家介绍一种我自己总结的方法, 就像上高中数学老师经常介绍的做题窍门, 学会了就能又快又好地解决问题啦.
3. 重新设计代码结构,将代码和并或者分离
所需材料: 一张纸, 一支笔. 我们先将引用关系用笔画在纸上, 看看循环引用到底是怎么形成的.
规定一下:
框框 中是文件名, 框框下边 是这个文件中的变量名.箭头 代表引用关系: 被引用指向引用.如果是文件引用的文件, 就画 框框 指向 框框 ; 如果是文件引用变量名, 就画 框框下的变量名 指向 框框 .具体看下边:
app.moudels.user
中的User
被引用, 同时其中又引用app.init
中的login_manager
, 形成了一个引用闭环, 即循环引用.login_manager
上, 那么我们就从它入手, 调整其位置, 解除循环引用关系. 当我们把login_manager
的定义从app.init
中移动到app.models.user
中后, 我们可以看到循环引用已经消失, 程序也可以正常运行了.app.init
)引用的其他文件(app.models.user
)中, 有对文件1的再次引用(login_manager
).login_manager
)想象成可以移动的东西, 将他在纸上移动, 直到闭环不复存在.