我可以将pymysql.connect()与"with"语句一起使用吗?

Pav*_*kov 9 python with-statement pymysql

以下是pymysql中的示例:

conn = pymysql.connect(...)
with conn.cursor() as cursor:
    cursor.execute(...)
    ...
conn.close()
Run Code Online (Sandbox Code Playgroud)

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

import pymysql
with pymysql.connect(...) as cursor:
    cursor.execute('show tables')
Run Code Online (Sandbox Code Playgroud)

(python 3,最新的pymysql)

Mik*_*ike 15

这看起来并不安全,如果你看这里,__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()
Run Code Online (Sandbox Code Playgroud)

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

您可以通过使用它创建多个游标来回收连接(游标的源在这里),游标方法如下所示:

def __enter__(self):
    return self

def __exit__(self, *exc_info):
    del exc_info
    self.close()
Run Code Online (Sandbox Code Playgroud)

所以他们自己关闭了.您可以创建单个连接,并在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()
Run Code Online (Sandbox Code Playgroud)

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

with get_connection(...) as con:
    with con.cursor() as cursor:
        cursor.execute(...)
Run Code Online (Sandbox Code Playgroud)


小智 7

正如有人指出的那样,Cursor 会自行处理,但是几天前,Connection 对上下文管理器的所有支持都被完全删除了,所以现在唯一的选择是编写你的:

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

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