正如我昨天提到的,我最近写了一些使用 imaplib 模块的代码。在这个过程中,我遇到了一些麻烦,其中一个是传统的麻烦,一个是我最近才体会到的新麻烦。
传统的烦恼是,imaplib 模块并不包裹它所使用的其他模块的错误。这给你留下了至少两个问题。第一个问题是,你得尝试捕捉一堆异常类来处理错误:
try:
c = ssl.create_default_context()
m = imaplib.IMAP4_SSL(host=host, ssl_context=c)
[...]
except (imaplib.IMAP4.error, ssl.SSLError, OSError) as e:
[...]
第二个问题是,我不确定我是否真的抓住了调用imaplib 模块可能引发的所有错误。该模块并没有记录这些错误,所以这个列表只是我在测试中能够引发的错误。这就是我多年前写过的不封装异常的根本缺陷;不封装异常,你就会使你所调用的模块成为你的 API 的隐含部分。那么你通常就不会去记录它。
我给imaplib模块加分,因为它的错误异常类是通过另一个类的属性访问的。我确信这有一个历史原因,但我真的希望它能作为 Python 3 移植的一部分被清理掉。在当前的 Python 3 源中,这些异常类实际上是IMAP4 类中的类:
class IMAP4:
[...]
class error(Exception): pass
class abort(error): pass
class readonly(abort): pass
[...]
另一个恼人的问题是,imaplib 模块没有实现任何形式的超时,无论是对单个操作还是对整个序列的操作。如果你不准备等待可能很长的时间(如果IMAP服务器出了问题),你需要自己通过imaplib 以外的方式添加某种超时,要么像 signal.setitimer() SIGALRM 处理程序,或者通过操作底层套接字来设置超时(尽管我读到过,这将导致问题,而且无论如何,你通常也会试图通过SSL工作)。对于我自己的程序,我选择了SIGALRM,但我有一个好处,那就是我所做的唯一事情就是IMAP。一个更复杂的程序可能不想因为IMAP方面的事情太慢而用SIGALRM 来炸毁自己。
当我写的程序大多是交互式运行,只做一件事的时候,超时并不是我过去考虑的事情,在这种情况下,超时是由用户按Ctrl-C键杀死整个程序来实现的,这是最合理的。自动测试程序和其他类似的东西非常关心超时,因为它们不想在服务器出错时挂起。事实上,可以用一种非常简单的方法使imaplib ,使其挂起相当长的时间:
m = imaplib.IMAP4_SSL(host=host, port=443)
你甚至不需要真正的回应,也不需要建立TLS会话;只要接受TCP连接就够了。这是相当危险的,因为 "接受连接然后挂起 "或多或少是系统在足够高的负载下的预期行为(接受连接是在内核中处理的,然后系统的负载太大,IMAP服务器无法运行)。
总的来说,我觉得imaplib 模块对于简单、直接的使用是可以的,但对于更多的东西来说,它并不是一个真正的基础。当然,你可以使用它,但你也可能要修补一些东西和解决一些问题。对我们来说,使用imaplib ,在这些问题上做文章是最简单的方法,但如果我想做更多,我可能会寻找一个第三方模块(或考虑更换语言)。