使用 `with` 语句关闭连接

Closing a connection with a `with` statement

我想要一个代表 IMAP 连接的 class 并将其与 with 语句一起使用,如下所示:

class IMAPConnection:
    def __enter__(self):
        connection = imaplib.IMAP4_SSL(IMAP_HOST)

        try:
            connection.login(MAIL_USERNAME, MAIL_PASS)
        except imaplib.IMAP4.error:
            log.error('Failed to log in')

        return connection

    def __exit__(self, type, value, traceback):
        self.close()

with IMAPConnection() as c:
    rv, data = c.list()
    print(rv, data)

自然这会失败,因为 IMAPConnections 没有属性 close。当 with 语句完成时,如何存储连接并将其传递给 __exit__ 函数?

您需要在 IMAPConnection class 中实现 __exit__() 功能。

__enter__() 函数在执行 with 块中的代码之前被调用,而 __exit__() 在退出 with 块时被调用。

下面是示例结构:

def __exit__(self, exc_type, exc_val, exc_tb):
    # Close the connection and other logic applicable
    self.connection.close()

查看:Explaining Python's 'enter' and 'exit' 了解更多信息。

您需要在对象属性中存储连接。像这样:

class IMAPConnection:
    def __enter__(self):
        self.connection = imaplib.IMAP4_SSL(IMAP_HOST)

        try:
            self.connection.login(MAIL_USERNAME, MAIL_PASS)
        except imaplib.IMAP4.error:
            log.error('Failed to log in')

        return self.connection

    def __exit__(self, type, value, traceback):
        self.connection.close()

您还想为您实施 list 方法 class。

编辑:我现在才意识到你的实际问题是什么。当你做 with SomeClass(*args, **kwargs) as cc 不是 __enter__ 方法返回的值。 cSomeClass 的实例。这是您从 __enter__ 返回连接并假设 c 表示连接的问题的根源。