Python 这种导入如何被认为是循环的(或者为什么我会收到“ImportError:cannotimportname EmailMessage”错误)
更新:Python 这种导入如何被认为是循环的(或者为什么我会收到“ImportError:cannotimportname EmailMessage”错误),python,python-import,circular-dependency,circular-reference,Python,Python Import,Circular Dependency,Circular Reference,更新: 错误(在这种特殊情况下)不是由循环导入引起的,而是由配置中的缺陷引起的。详见下文 我正在使用: 0.12.2 3.6.1 我正在使用Flask构建一个web应用程序,除此之外,我还需要能够向用户发送邮件。我已经构建了一个单独的Python模块,它将负责邮件处理。虽然在我将电子邮件处理模块添加到我的应用程序后,我遇到了一个奇怪的问题(至少在我看来是这样)import 以下是我遇到的(隔离)导入问题: app.py from flask import Flask from test_
错误(在这种特殊情况下)不是由循环导入引起的,而是由配置中的缺陷引起的。详见下文
我正在使用:
- 0.12.2
- 3.6.1
import
以下是我遇到的(隔离)
导入问题:
app.py
from flask import Flask
from test_mail import EmailTool
app = Flask(__name__)
@app.route('/')
def index():
return 'Testing!'
from email.message import EmailMessage
class EmailTool(object):
pass
测试邮件.py
from flask import Flask
from test_mail import EmailTool
app = Flask(__name__)
@app.route('/')
def index():
return 'Testing!'
from email.message import EmailMessage
class EmailTool(object):
pass
启动我的应用程序并进入索引(即/
)后,我收到:
Traceback (most recent call last):
File "/app.py", line 2, in <module>
from tmp_test_mail import EmailTool
File "/test_mail.py", line 1, in <module>
from email.message import EmailMessage
ImportError: cannot import name EmailMessage
这样我就不会出错
寻找可能的原因和解决方案使我相信(,),它很可能与循环引用有关。尽管在阅读了所有提到的材料并隔离了问题的原因之后,我仍然看不出它是一个怎样的循环参考。所以我的结论是,要么它不是循环的,原因在于其他原因,要么它是循环的,我在这里遗漏了一些明显的东西
我请求帮助理解以下内容:
上述案例是否被视为循环参考?(如果是,它实际上是以什么方式循环的
为什么当我从email.message导入EmailMessage
中执行操作时会出现错误,但如果我执行导入email
操作,则不会出现错误
要回答这两个问题,请执行以下操作:
首先
不,以上提供的代码不应是循环的,除非email.message
包含对app
模块的引用,假设app
是有效模块
秒
从email
而不是email.message
导入不会导致任何错误,因为您没有导入(似乎)有问题的EmailMessage
类,因为它位于email.message
中,而不是email
。我的理论是,它是由一些导入循环返回到email.message
模块中的app
模块引起的
注:
在撰写本文时,我并不知道email
或email.message
是标准(3.6.x)库的一部分,因为我从未使用过与这些模块相关的任何东西(而且我也不经常使用python 3.x),因此我认为这是由作者建议的循环引用引起的。事实证明(并在报告中指出),这是由TL引起的;DR:实际问题与循环依赖性无关-结果是我的虚拟环境配置错误(Python版本实际上是2.7.10,正如作者在评论中所建议的)
我是如何找到原因的(作为调试Pythonvenv
的方法集发布的,这可能对我自己和其他人都很方便):
在阅读了对我的查询的评论(“特别是我的评论”)之后,我立即检查了我运行我的应用程序时使用的Python版本(尽管我在发布问题之前就检查了它-在这类事情上,你再小心也不为过=)。
正在运行(在虚拟环境中):
给了我(正如我所预料的):
不过,我不相信。正如this answers所建议的那样:并且,我已经在这两个模块的代码中添加了以下内容:app.py
和test\u mail.py
(为了检查它们实际运行的Python版本):
它的输出(让我惊讶):
好的,很明显这里出了点问题。我决定更新我的virtualenv
设置的基本知识。我偶然发现的,建议将pip--version
作为设置过程的第二步(在python--version
之后)。我没有什么可松懈的,所以我运行了它(当然是在虚拟环境中),并且(让我惊讶的是)它给了我:
pip 9.0.1 from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages (python 2.7)
所以,在虚拟环境中使用的某种方式是系统级的
在这一点上,我怀疑我的应用程序是从virtualenv
运行的。按照(和注释)中的配方,我编写并添加了以下代码片段到app.py
和test\u mail.py
:
import sys
...
if hasattr(sys, 'real_prefix'):
print('Python 2 venv')
elif (hasattr(sys, 'base_prefix') and sys.prefix != sys.base_prefix):
print('Python 3 venv')
else:
print('Not venv!')
(此时)它正在打印而不是venv,这并不奇怪代码>
调试当前虚拟环境到底出了什么问题似乎花费了大量的时间。所以,我最后做的是:
- 通过
pip卸载从系统级(出于某种原因安装在那里)移除Flask
和相关软件包(itsDanger
、Jinja2
、MarkupSafe
、Werkzeug
)
- 使用python3-m venv重新创建虚拟环境
现在,回答我自己的问题:
我问题中的代码不包含循环引用
尝试从email.message导入EmailMessage
执行后出现错误,因为实际使用的是Python 2.7.10,如果我们查看此版本的Python,就会发现它根本不包含名为EmailMessage
的类。而,不包含名为EmailMessage
的类
您确定它是python 3.6吗?不,上面的代码不是循环引用,当然,除非email.message
模块从app
导入,否则它将是循环引用
2.7.10
pip 9.0.1 from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages (python 2.7)
import sys
...
if hasattr(sys, 'real_prefix'):
print('Python 2 venv')
elif (hasattr(sys, 'base_prefix') and sys.prefix != sys.base_prefix):
print('Python 3 venv')
else:
print('Not venv!')