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

问题描述 投票:0回答:5

以下为 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)

python with-statement pymysql
5个回答
20
投票

这看起来不安全,如果你看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 子句并没有关闭连接,这意味着它会徘徊。我不知道他们为什么这样做。不过,您可以制作自己的包装纸来做到这一点。

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

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(...)

8
投票

正如所指出的,游标会自行处理,但是连接对上下文管理器的所有支持就在几天前被完全删除,所以现在唯一的选择是编写你的:

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

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


2
投票

Pymysql 的最新更新 (https://github.com/PyMySQL/PyMySQL/pull/886/files) 现在在退出时调用

close()
,因此支持使用
with
并反映在其文档中。

import pymysql.cursors

# Connect to the database
connection = pymysql.connect(host='localhost',
                             user='user',
                             password='passwd',
                             database='db',
                             cursorclass=pymysql.cursors.DictCursor)

with connection:
.
.


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 年底解决该问题时拒绝了这种方法。


0
投票

从 PyMySQL v.1.1.1 开始,连接对象一个上下文管理器,因此可以在

with
语句中使用:

with pymysql.connect(**connect_args) as conn:
    with conn.cursor() as cursor:
        # do something with the cursor

离开

with
代码块时,连接将被关闭,因此如果您想在多个上下文中使用相同的连接,请不要这样做。此行为与连接上下文管理器在其他数据库访问库(例如
psycopg2
sqlite
)中的工作方式不同,其中退出
with
块只是提交或回滚事务。就目前而言,Python DBAPI 根本不需要连接类来实现
__enter__
__exit__
方法,这不会促进实现的一致性。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.