How is this kind of import considered circular (or why am I getting "ImportError: cannot import name EmailMessage" error)
How is this kind of import considered circular (or why am I getting "ImportError: cannot import name EmailMessage" error)
更新:
错误(在这种特殊情况下)不是由循环导入引起的,而是由下面 virtualenv
configuration. See 中的缺陷引起的,以供详细说明。
我正在使用:
我正在使用 Flask 构建一个 Web 应用程序,除其他外,我需要能够向用户发送邮件。我已经建立了一个单独的 Python 模块,它将负责邮件处理。虽然我遇到了一个奇怪的(至少在我看来)import
问题,但在我将电子邮件处理模块添加到我的应用程序之后。
这是我遇到的(绝缘)import
问题:
app.py
from flask import Flask
from test_mail import EmailTool
app = Flask(__name__)
@app.route('/')
def index():
return 'Testing!'
test_mail.py
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
我已经更改了 test_mail.py 的代码,以确保可以访问 email
模块:
import email
class EmailTool(object):
pass
这样我就不会报错了。
寻找可能的原因和解决方案使我相信 (1, 2, 3, 4, 5),它很可能与循环引用有关。尽管阅读了所有提到的材料并隔离了问题原因,但我仍然看不出它是如何成为 circular 参考的。所以我得出结论,要么它不是循环的,原因在于其他东西,要么它是循环的,我在这里遗漏了一些明显的东西。
我请求帮助以理解以下内容:
- 以上案例是否属于循环引用? (如果是,它实际上是循环)是什么?
- 为什么我在执行
from email.message import EmailMessage
时会收到错误消息,但如果我执行 import email
却不会收到错误消息?
回答你的两个问题:
第一
不,上面提供的代码不应该是循环的,除非email.message
包含对app
模块的引用,假设app
是一个有效的模块。
第二
从 email
而不是 email.message
导入不会导致任何错误,因为您没有导入(看似)有问题的 EmailMessage
class 因为它位于 email.message
,而不是 email
。我的理论是,它是由一些导入循环回到 email.message
模块中的 app
模块引起的。
注:
在撰写本文时,我并不知道 email
或 email.message
是标准 (3.6.x) 库的一部分,因为我从未使用过任何与这些模块(而且我不经常使用 python 3.x<),因此我认为这是由作者建议的 循环引用 引起的。事实证明(并在 ) this was caused by .
中指出
TL;DR: 实际问题与循环依赖无关——结果是我的虚拟环境配置错误 (Python 版本实际上是 2.7.10,正如 hjpotter92) 在评论中所建议的那样。
我是如何发现它的原因的(作为调试您的 Python venv
的食谱集发布,以后可能对我自己以及希望对其他人有用):
在阅读了对我的问题的评论(特别是hjpotter92的评论)后,我赶紧检查了 [=77] 中 Python 的版本=]virtualenv
我 运行 我的应用程序来自(即使我在发布问题之前已经检查过它 - 你在这种事情上不能太小心 =)。
运行(在虚拟环境中):
python --version
给了我(正如我所料):
Python 3.6.1
虽然我不相信 =)。正如这个答案所建议的:1 and 2,我在两个模块的代码中添加了以下内容:app.py
和 test_mail.py
(为了检查 Python 的哪个版本实际上是运行:
import sys
...
print(sys.version)
它正在输出(令我感到惊讶):
2.7.10
好吧,显然这里有问题。我决定复习一下 virtualenv
设置的基础知识。我偶然发现的 first article 建议将 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)
所以,不知何故 pip
在虚拟环境中使用的是系统级别的...
此时我怀疑我的应用程序是否 运行ning 来自 virtualenv
。根据 this answer 的食谱( 和评论 ),我编写并添加到 app.py
和 test_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!')
它正在打印 Not venv!
。
不足为奇(此时)
- 调试当前虚拟环境到底出了什么问题似乎很费时间。所以,我最终做了什么:
- 从系统级别(安装在那里,对于一些原因)通过
pip uninstall <package_name>
.
- 正在使用
python3 -m venv <env_name>
重新创建虚拟环境
现在,回答我自己的问题:
- 我问题中的代码不包含循环引用。
- 尝试执行
from email.message import EmailMessage
后出现错误,因为实际使用了 Python 2.7.10,如果我们查看 source code of message.py
for this version of Python, we will see that it simply does not contain a class named EmailMessage
. While the source code of message.py
for Python 3.6.* library,确实包含 class 命名为 EmailMessage
.
更新:
错误(在这种特殊情况下)不是由循环导入引起的,而是由下面 virtualenv
configuration. See
我正在使用:
我正在使用 Flask 构建一个 Web 应用程序,除其他外,我需要能够向用户发送邮件。我已经建立了一个单独的 Python 模块,它将负责邮件处理。虽然我遇到了一个奇怪的(至少在我看来)import
问题,但在我将电子邮件处理模块添加到我的应用程序之后。
这是我遇到的(绝缘)import
问题:
app.py
from flask import Flask
from test_mail import EmailTool
app = Flask(__name__)
@app.route('/')
def index():
return 'Testing!'
test_mail.py
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
我已经更改了 test_mail.py 的代码,以确保可以访问 email
模块:
import email
class EmailTool(object):
pass
这样我就不会报错了。
寻找可能的原因和解决方案使我相信 (1, 2, 3, 4, 5),它很可能与循环引用有关。尽管阅读了所有提到的材料并隔离了问题原因,但我仍然看不出它是如何成为 circular 参考的。所以我得出结论,要么它不是循环的,原因在于其他东西,要么它是循环的,我在这里遗漏了一些明显的东西。
我请求帮助以理解以下内容:
- 以上案例是否属于循环引用? (如果是,它实际上是循环)是什么?
- 为什么我在执行
from email.message import EmailMessage
时会收到错误消息,但如果我执行import email
却不会收到错误消息?
回答你的两个问题:
第一
不,上面提供的代码不应该是循环的,除非email.message
包含对app
模块的引用,假设app
是一个有效的模块。
第二
从 email
而不是 email.message
导入不会导致任何错误,因为您没有导入(看似)有问题的 EmailMessage
class 因为它位于 email.message
,而不是 email
。我的理论是,它是由一些导入循环回到 email.message
模块中的 app
模块引起的。
注:
在撰写本文时,我并不知道 email
或 email.message
是标准 (3.6.x) 库的一部分,因为我从未使用过任何与这些模块(而且我不经常使用 python 3.x<),因此我认为这是由作者建议的 循环引用 引起的。事实证明(并在
TL;DR: 实际问题与循环依赖无关——结果是我的虚拟环境配置错误 (Python 版本实际上是 2.7.10,正如 hjpotter92) 在评论中所建议的那样。
我是如何发现它的原因的(作为调试您的 Python venv
的食谱集发布,以后可能对我自己以及希望对其他人有用):
在阅读了对我的问题的评论(特别是hjpotter92的评论)后,我赶紧检查了 [=77] 中 Python 的版本=]
virtualenv
我 运行 我的应用程序来自(即使我在发布问题之前已经检查过它 - 你在这种事情上不能太小心 =)。
运行(在虚拟环境中):python --version
给了我(正如我所料):
Python 3.6.1
虽然我不相信 =)。正如这个答案所建议的:1 and 2,我在两个模块的代码中添加了以下内容:
app.py
和test_mail.py
(为了检查 Python 的哪个版本实际上是运行:import sys ... print(sys.version)
它正在输出(令我感到惊讶):
2.7.10
好吧,显然这里有问题。我决定复习一下
virtualenv
设置的基础知识。我偶然发现的 first article 建议将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)
所以,不知何故
pip
在虚拟环境中使用的是系统级别的...此时我怀疑我的应用程序是否 运行ning 来自
virtualenv
。根据 this answer 的食谱( 和评论 ),我编写并添加到app.py
和test_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!')
它正在打印
Not venv!
。 不足为奇(此时)
- 调试当前虚拟环境到底出了什么问题似乎很费时间。所以,我最终做了什么:
- 从系统级别(安装在那里,对于一些原因)通过
pip uninstall <package_name>
. - 正在使用
python3 -m venv <env_name>
重新创建虚拟环境
- 从系统级别(安装在那里,对于一些原因)通过
现在,回答我自己的问题:
- 我问题中的代码不包含循环引用。
- 尝试执行
from email.message import EmailMessage
后出现错误,因为实际使用了 Python 2.7.10,如果我们查看 source code ofmessage.py
for this version of Python, we will see that it simply does not contain a class namedEmailMessage
. While the source code ofmessage.py
for Python 3.6.* library,确实包含 class 命名为EmailMessage
.