jmi*_*loy 19 python mysql mysql-python contextmanager
MySQLdb Connections有一个基本的上下文管理器,可以在enter上创建一个游标,在退出时回退或提交,并且隐式不会抑制异常.来自连接源:
def __enter__(self):
if self.get_autocommit():
self.query("BEGIN")
return self.cursor()
def __exit__(self, exc, value, tb):
if exc:
self.rollback()
else:
self.commit()
Run Code Online (Sandbox Code Playgroud)
那么,有没有人知道为什么光标在退出时没有关闭?
起初,我认为这是因为关闭游标没有做任何事情,并且游标只有一个关闭方法来参考Python DB API(参见本答案的评论).但是,事实是关闭光标会烧掉剩余的结果集(如果有),并禁用光标.从光标源:
def close(self):
"""Close the cursor. No further queries will be possible."""
if not self.connection: return
while self.nextset(): pass
self.connection = None
Run Code Online (Sandbox Code Playgroud)
在退出处关闭光标会很容易,所以我不得不假设它没有故意完成.另一方面,我们可以看到,当一个游标被删除时,无论如何它都会被关闭,所以我猜垃圾收集器最终会绕过它.我对Python中的垃圾收集知之甚少.
def __del__(self):
self.close()
self.errorhandler = None
self._result = None
Run Code Online (Sandbox Code Playgroud)
另一个猜测是,您可能希望在with块之后重新使用光标.但我想不出你为什么需要这样做的任何理由.难道你不能总是在其上下文中使用游标,并且只为下一个事务使用单独的上下文吗?
要非常清楚,这个例子显然没有意义:
with conn as cursor:
cursor.execute(select_stmt)
rows = cursor.fetchall()
Run Code Online (Sandbox Code Playgroud)
它应该是:
with conn as cursor:
cursor.execute(select_stmt)
rows = cursor.fetchall()
Run Code Online (Sandbox Code Playgroud)
这个例子也没有意义:
# first transaction
with conn as cursor:
cursor.execute(update_stmt_1)
# second transaction, reusing cursor
try:
cursor.execute(update_stmt_2)
except:
conn.rollback()
else:
conn.commit()
Run Code Online (Sandbox Code Playgroud)
它应该只是:
# first transaction
with conn as cursor:
cursor.execute(update_stmt_1)
# second transaction, new cursor
with conn as cursor:
cursor.execute(update_stmt_2)
Run Code Online (Sandbox Code Playgroud)
再次,关闭退出光标会有什么危害,有什么好处不关闭呢?
J R*_*ape 10
直接回答你的问题:在一个with区块结束时我无法看到任何伤害.我不能说为什么在这种情况下没有这样做.但是,由于在这个问题上缺乏活动,我对代码历史进行了搜索,并会对可能无法调用的原因提出一些想法(猜测):close()
旋转调用nextset()可能会引发异常的可能性很小- 可能已经观察到并且被视为不合需要.这可能是为什么较新版本cursors.py包含此结构的原因close():
def close(self):
"""Close the cursor. No further queries will be possible."""
if not self.connection:
return
self._flush()
try:
while self.nextset():
pass
except:
pass
self.connection = None
Run Code Online (Sandbox Code Playgroud)有一些(有点遥远的)潜力可能需要一些时间才能完成所有剩余的结果.因此close()可能无法调用以避免进行一些不必要的迭代.我认为,你是否认为值得保存这些时钟周期是主观的,但你可以按照"如果没有必要,不要这样做"的方式进行争论.
浏览sourceforge提交,该功能在2007年通过此提交添加到主干,看起来这部分connections.py从那以后没有改变.这是基于此提交的合并,它具有消息
如http://docs.python.org/whatsnew/pep-343.html中 所述,为with语句添加Python-2.5支持请测试
你引用的代码从那以后就没有改变过.
这促使我最后的想法 - 它可能只是一个刚刚起作用的第一次尝试/原型,因此从未改变过.
您链接到旧版连接器的源.我注意到有同一库更积极的叉子在这里,这是我在第1点链接到我的关于"新版本"的意见.
请注意,该模块的最新版本已经实施__enter__()和__exit__()内部cursor本身:在这里看到. __exit__()这里做了 调用self.close(),也许这提供了一种更标准的方式来使用with语法,例如
with conn.cursor() as c:
#Do your thing with the cursor
Run Code Online (Sandbox Code Playgroud)
NB我想我应该添加,据我所知,垃圾收集(不是专家)一旦没有引用conn,它将被解除分配.此时将不会引用游标对象,它也将被解除分配.
但是,调用cursor.close()并不意味着它将被垃圾收集.它只是烧掉结果并设置连接None.这意味着它无法重复使用,但不会立即进行垃圾回收.您可以通过cursor.close()在with阻止之后手动调用然后打印某些属性来说服自己cursor
NB 2我认为这是一种有点不同寻常的with语法用法,conn因为它已经存在于外部范围内 - 不像说,更常见with open('filename') as f:的是在with块结束后没有任何对象挂在引用上.
| 归档时间: |
|
| 查看次数: |
2016 次 |
| 最近记录: |