gpt4 book ai didi

Python 为什么不能为 sqlite3 游标编写上下文管理器?

转载 作者:IT王子 更新时间:2023-10-29 06:23:25 24 4
gpt4 key购买 nike

这应该可以工作,但只是说没有股票表 - 应该在上下文管理器内的某处丢失了连接?

import sqlite3
from contextlib import contextmanager

@contextmanager
def doquery(conn, q, params=()):
c = conn.cursor()
c.execute(q, params)
conn.commit()
yield c
c.close()

with sqlite3.connect(':memory:') as db:
doquery(db,'''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')

doquery(db,"""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")

with doquery(db, 'select * from stocks') as r:
for row in r:
print row

最佳答案

问题在于您使用上下文管理器的方式。调用 doquery 只是创建一个上下文管理器对象 - 您需要在 with 语句中使用它,该语句调用它的 __enter____exit__ 适当的方法。例如,尝试以下操作:

from contextlib import contextmanager

@contextmanager
def enter_exit(text):
print('entering')
yield text
print('exiting')

print(enter_exit('attempt 1'))

with enter_exit('attempt 2') as t:
print(t)

我得到的输出是:

<contextlib._GeneratorContextManager object at 0xcf3e90>
entering
attempt 2
exiting

您可能需要重新阅读有关 the with statementcontextlib 的文档。

您的代码的另一个问题是,如果 c.executeconn.commit 引发异常,则不会调用 c.close - 我不知道这是否真的有必要,但大概这就是您首先要使用上下文管理器而不是函数的原因。以下更改应该可以解决这两个问题:

import sqlite3
from contextlib import contextmanager

@contextmanager
def doquery(conn, q, params=()):
c = conn.cursor()
try:
c.execute(q, params)
conn.commit()
yield c
finally:
c.close()

with sqlite3.connect(':memory:') as db:
with doquery(db,'''create table stocks
(date text, trans text, symbol text,
qty real, price real)'''):
pass

with doquery(db,"""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)"""):
pass

with doquery(db, 'select * from stocks') as r:
for row in r:
print(row)

但是,我认为这不是最简洁的方法。据我所知,没有理由创建三个单独的 cursor 对象 - 您可以为每个查询使用相同的对象。我认为对 conn.commit 的调用实际上也不是必需的 - 使用数据库连接作为上下文管理器将自动提交事务,或者在引发异常时回滚它们(参见 sqlite3 module documentation ) .

编辑:这是一个更简洁的版本,它仍然有效。我真的不知道关闭游标实际上做了什么 - 它可能没有必要(Cursor.close 似乎甚至没有记录)。

import sqlite3
from contextlib import closing

with sqlite3.connect(':memory:') as db:
with closing(db.cursor()) as c:
c.execute('''create table stocks
(date text, trans text, symbol text,
qty real, price real)''')
c.execute("""insert into stocks
values ('2006-01-05','BUY','RHAT',100,35.14)""")
c.execute('select * from stocks')
for row in c:
print(row)

关于Python 为什么不能为 sqlite3 游标编写上下文管理器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10029403/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com