【问题标题】:Can I use pymysql.connect() with "with" statement?我可以将 pymysql.connect() 与“with”语句一起使用吗?
【发布时间】:2015-09-21 18:12:44
【问题描述】:

以下是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


【解决方案1】:

这看起来不安全,如果您查看 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(...)

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    作为替代方案,因为我想支持连接的上下文管理器模式,所以我使用猴子补丁来实现它。不是最好的方法,但它是一些东西。

    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
    
    

    这种方法适用于我的用例。我希望在 Connection 类中有 __enter____exit__ 方法。然而,开发人员在 2018 年底解决该问题时拒绝了这种方法。

    【讨论】:

      猜你喜欢
      • 2012-07-29
      • 2016-01-02
      • 2012-06-24
      • 1970-01-01
      • 2019-06-17
      • 1970-01-01
      • 2011-02-08
      • 2021-07-01
      • 2020-03-26
      相关资源
      最近更新 更多