英文:
Python3 return multiple contextmanagers from a function to be used in a single with statement
问题
根据psycopg2文档https://www.psycopg.org/docs/usage.html#transactions-control,con
对象管理事务并负责提交和回滚数据库事务。因此,在with
语句中同时需要con
和con.cursor()
以正确管理提交/回滚。
现在,您想要多次重复代码中的with
部分,以执行多个事务,例如:
con = psycopg2.connect()
with con, con.cursor() as c:
c.execute() # 这里有一些查询
with con, con.cursor() as c:
c.execute() # 这里有另一个查询
...
with con, con.cursor() as c:
c.execute() # 这里有最终的查询
这种方法有效,但需要在每个with
块中复制粘贴con, con.cursor()
部分。
现在,您想知道在Python中是否可以创建一个函数,返回一个可以直接传递给with
语句的内容,以将con, con.cursor()
简化为some_custom_function()
。
以下是一个示例代码:
con = psycopg2.connect()
def cursor():
return con, con.cursor() # 这不起作用
with cursor() as c:
c.execute() # 这里有一些查询
with cursor() as c:
c.execute() # 这里有另一个查询
...
with cursor() as c:
c.execute() # 这里有最终的查询
(您可能会想知道为什么要这样做,但con.cursor()
方法还接受参数,如cursor_factory=psycopg2.extras.RealDictCursor
。然后,我还需要在每个with
语句中重复这些参数。但为了简化这个示例,我省略了这一点。)
英文:
Given:
con = psycopg2.connect()
with con, con.cursor() as c:
c.execute() # some query inside here
According to the psycopg2 documentation https://www.psycopg.org/docs/usage.html#transactions-control, the con object manages the transaction and takes care of commit and rollback of the db transaction. So both the con
and con.cursor()
are required in the with
statement to properly manage commit/rollback
Now I want repeat the with
part of the code multiple times, to do multiple transactions, such as
con = psycopg2.connect()
with con, con.cursor() as c:
c.execute() # some query inside here
with con, con.cursor() as c:
c.execute() # another query inside here
...
with con, con.cursor() as c:
c.execute() # final query inside here
This works but this requires me to copy paste the con, con.cursor()
part of the with
statement for every with
block.
Now I was wondering if it is possible in python to create a function that returns something that I can pass directly to the with
statement to reduce con, con.cursor()
to some_custom_function()
Something along these lines:
con = psycopg2.connect()
def cursor():
return con, con.cursor() # this doesn't work
with cursor() as c:
c.execute() # some query inside here
with cursor() as c:
c.execute() # another query inside here
...
with cursor() as c:
c.execute() # final query inside here
(You may be wondering why, but the con.cursor()
method also takes arguments such as cursor_factory=psycopg2.extras.RealDictCursor
. Then I would have to repeat those arguments with every with
statement as well. But for simplicity of this example, I've left that out of the question.)
答案1
得分: 3
尝试使用 contextlib.contextmanager
:
from contextlib import contextmanager
import psycopg2
con = psycopg2.connect(...)
@contextmanager
def with_txn_and_cursor():
with con, con.cursor(cursor_factory=RealDictCursor) as cur:
yield cur
with with_txn_and_cursor() as cur:
cur.execute(...)
如果您需要同时使用 con
和 cur
,从上下文管理器中返回一个元组。
@contextmanager
def with_txn_and_cursor_2():
with con, con.cursor(cursor_factory=RealDictCursor) as cur:
yield (con, cur)
with with_txn_and_cursor_2() as (con, cur):
cur.execute(...)
英文:
Try contextlib.contextmanager
:
from contextlib import contextmanager
import psycopg2
con = psycopg2.connect(...)
@contextmanager
def with_txn_and_cursor():
with con, con.cursor(cursor_factory=RealDictCursor) as cur:
yield cur
with with_txn_and_cursor() as cur:
cur.execute(...)
If you need both the con
and cur
, yield a tuple out of the context manager.
@contextmanager
def with_txn_and_cursor_2():
with con, con.cursor(cursor_factory=RealDictCursor) as cur:
yield (con, cur)
with with_txn_and_cursor_2() as (con, cur):
cur.execute(...)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论