【问题标题】:Why do I have to "from module import" with the email module in python?为什么我必须使用 python 中的电子邮件模块“从模块导入”?
【发布时间】:2014-07-03 21:22:38
【问题描述】:

抱歉,如果问题没有准确,我很难正确表达这个问题。

我正在尝试使用电子邮件模块创建一个简单的纯文本电子邮件,并在满足某些条件时发送。我遇到了各种异常行为,并想了解它。我从官方示例 (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")

它失败并出现同样的错误。

为了让那个小 sn-p 运行,我必须这样做

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() 之后才起作用?

通常我非常擅长寻找答案,但我认为在这种情况下我只是不知道要搜索什么。 “模块对象没有属性”有很多解决方案,但其中大多数是重复命名文件、循环导入、调用不存在的函数或检查属性是否存在。他们似乎都没有解决导入行为的工作原理。我的代码结构是错误的还是电子邮件模块只是对我起作用?

【问题讨论】:

  • 您的脚本是否名为email.py? :) 我之前被那个绊倒了,以系统模块命名我的模块。
  • 您可能在某处犯了一个小的剪切和粘贴错误,因为您的原始代码块没有按说明工作。它需要有from email.message import EmailMessage from email.headerregistry import Address
  • @shavenwarthog 不,我在上一段中提到过。
  • @VidhyaG 不,非常适合我。只需要在第三行到最后一行使用真正的 gmail 登录。甚至检查了 mailinator 页面,它确实已交付。不知道为什么它不适合你。
  • 对不起。是的,我的错。您正在使用 Python 3.3 中引入的临时模块 (email.headerregistry) legacy.python.org/dev/peps/pep-0411

标签: python email import attributes smtplib


【解决方案1】:

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 这样的现代工具能够很好地解决这种缺陷。

【讨论】:

  • 这解决了大部分问题。知道为什么当您尝试在email.message.EmailMessage() 之前调用email.headderregistry.Address 时它会失败,但如果您先调用EmailMessage() 则工作正常?
  • @StackofPancakes 我希望第一次实例化 EmailMessage 会导致导入 email.headerregistry
  • 谢谢,这是我第一次遇到一个模块在使用import module_name 之后表现如此怪异。我想以后如果再遇到这种情况我会直接导入模块的特定部分。
  • @StackofPancakes 我同意这令人惊讶,但它通常被认为是import package 不一定导入所有子包的功能——毕竟,有些包可能非常大。 真正令人惊讶的是,即使您导入子模块,只要其他人在您尝试访问子模块之前导入子模块,您就会得到子模块。跨度>
猜你喜欢
  • 1970-01-01
  • 2020-05-16
  • 2011-10-15
  • 2011-05-09
  • 2012-03-07
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
相关资源
最近更新 更多