我可以使用pymysql.connect()和"和#34;声明?

时间:2015-07-03 22:02:21

标签: python with-statement pymysql

以下是pymysql中的示例:

conn = pymysql.connect(...)
with conn.cursor() as cursor:
    cursor.execute(...)
    ...
conn.close()

我可以使用以下内容,还是会留下一段挥之不去的连接? (它成功执行)

import pymysql
with pymysql.connect(...) as cursor:
    cursor.execute('show tables')

(python 3,最新的pymysql)

3 个答案:

答案 0 :(得分:13)

这看起来并不安全,如果您查看here__enter____exit__函数就会在with子句中调用。对于pymysql连接,它们看起来像这样:

def __enter__(self):
    """Context manager that returns a Cursor"""
    return self.cursor()

def __exit__(self, exc, value, traceback):
    """On successful exit, commit. On exception, rollback"""
    if exc:
        self.rollback()
    else:
        self.commit()

所以它看起来不像exit子句关闭了连接,这意味着它会挥之不去。我不确定他们为什么这样做。你可以制作自己的包装器来做到这一点。

您可以通过使用(the source for cursors is here)创建多个游标来回收连接,游标方法如下所示:

def __enter__(self):
    return self

def __exit__(self, *exc_info):
    del exc_info
    self.close()

所以他们确实关闭了自己。您可以创建单个连接,并在with子句中将其与多个游标重用。

如果要隐藏关闭with子句后面的连接的逻辑,例如一个上下文管理器,一个简单的方法就是这样:

from contextlib import contextmanager
import pymysql


@contextmanager
def get_connection(*args, **kwargs):
    connection = pymysql.connect(*args, **kwargs)
    try:
        yield connection
    finally:
        connection.close()

然后您可以像这样使用该上下文管理器:

with get_connection(...) as con:
    with con.cursor() as cursor:
        cursor.execute(...)

答案 1 :(得分:2)

正如所指出的那样,Cursor会自己照顾自己,但是几天前Connection完全取消了对上下文管理器的所有支持,所以现在唯一的选择就是编写您的:

https://github.com/PyMySQL/PyMySQL/pull/763

https://github.com/PyMySQL/PyMySQL/issues/446

答案 2 :(得分:1)

作为替代方案,由于我想支持连接的上下文管理器模式,因此我使用了猴子补丁来实现它。不是最好的方法,但这是什么。

import pymysql


MONKEYPATCH_PYMYSQL_CONNECTION = True


def monkeypatch_pymysql_connection():
    Connection = pymysql.connections.Connection

    def enter_patch(self):
        return self

    def exit_patch(self, exc, value, traceback):
        try:
            self.rollback()  # Implicit rollback when connection closed per PEP-249
        finally:
            self.close()

    Connection.__enter__ = enter_patch
    Connection.__exit__ = exit_patch


if MONKEYPATCH_PYMYSQL_CONNECTION:
    monkeypatch_pymysql_connection()
    MONKEYPATCH_PYMYSQL_CONNECTION = False  # Prevent patching more than once

这种方法适用于我的用例。我希望在__enter__类中使用__exit__Connection方法。但是,当开发人员在2018年底解决该问题时,该方法遭到了开发人员的拒绝。