为什么我必须从模块导入""与python中的电子邮件模块?

时间:2014-07-03 21:22:39

标签: python email import attributes smtplib

很抱歉,如果问题没有找到,我很难正确地填写这个问题。

我尝试使用电子邮件模块创建简单的纯文本电子邮件,并在满足特定条件时发送。我正在遇到各种异常行为,并希望了解它。我开始从官方示例(https://docs.python.org/3.4/library/email-examples.html)中抽取一个简单的测试,它运行良好。当我开始尝试在我的项目中实现这一点时,我开始得到各种"'module' object has no attribute 'something'"。我可以运行这样的东西,它工作正常

import email
import smtplib

# Create message object
msg = email.message.EmailMessage()

# Create the from and to Addresses
from_address = email.headerregistry.Address("Stack of Pancakes", "pancakes@gmail.com") 
to_address = email.headerregistry.Address("Joe", "pythontest@mailinator.com")

# Create email headers
msg['Subject'] = "subject of email"
msg['From'] = from_address
msg['To'] = to_address

#
email_content = "This is a plain text email"
msg.set_content(email_content)

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("pancakes@gmail.com", "password")
server.send_message(msg)
server.quit()

这完美无缺。但是,如果我以不同的方式订购东西,那么事情就会开始破碎,我不明白为什么。例如,如果我将from_addressto_address行放在上面调用EmailMessage的位置

import email
import smtplib

# Create the from and to Addresses
from_address = email.headerregistry.Address("Stack of Pancakes", "pancakes@gmail.com") 
to_address = email.headerregistry.Address("Joe", "pythontest@mailinator.com")

# Create message object
msg = email.message.EmailMessage()

... other code

它以'module' object has no attribute 'headerregistry'失败。为什么EmailMessage创建允许其他代码正常运行?

事实上,如果我有一个只包含此

的文件
import email

to_address = email.headerregistry.Address("joe", "joe@joe.com")

失败并出现同样的错误。

为了让那个小片段能够运行,我必须这样做

from email.headerregistry import Address

to_address = Address("joe", "joe@joe.com")

或者,这真的很奇怪,我可以让它运行

import email
import smtplib

email.message.EmailMessage()
to_address = email.headerregistry.Address("joe", "joe@joe.com")

但如果我删除了import smtplib,它会再次失败,即使我在这4行中没有使用smtplib中的任何内容。


我相当肯定我可以继续尝试我能想到的每一个组合并使其正常工作,但我更愿意理解这种行为。这样我就会更有信心在生产环境中运行代码。

为什么我不能只调用import email并使用email.headderregistry.Address声明我的对象,为什么我必须使用from email.headerregistry import Address显式导入该特定功能?为什么用import smtplib进行编译但没有它就失败了。为什么只有在调用EmailMessage()后才能工作?

通常我很擅长寻找答案,但我认为在这种情况下我不知道该搜索什么。对于"模块对象有一大堆解决方案没有属性",但是大多数是重复的命名文件,循环导入,不存在的调用函数或检查属性是否存在。他们似乎都没有解决导入行为如何运作的问题。我是在构建错误的代码还是电子邮件模块正在对我采取行动?

1 个答案:

答案 0 :(得分:5)

import email不会自动导入email包中的所有模块。这意味着,为了使用email.headerregistry,您必须导入它,这可以很简单:

import email.headerregistry

之后,您就可以使用email.headerregistry.Address

您的代码在编写from email.headerregistry import Address后也可以正常工作,因为该语句在内部执行(等效于)import email.headerregistry以加载模块并获取Address。同样,smtplib导入email个相关模块,其中一些可能导入email.headerregistry

总结:一旦任何模块执行导入email.headerregistry,该子模块对导入email所有模块都可见,即使他们从未明确要求email.headerregistry。导入模块的事实可以使不相关的包的子模块作为副作用可以导致令人讨厌的错误,其中模块仅在某些其他模块之后导入时才起作用。幸运的是,像pylint和Eclipse的pydev这样的现代工具很好地解决了这种陷阱。