是否在Python数据库API中指定的连接对象的__enter__和__exit__行为?

Mar*_*ery 9 python database api specifications mysql-python

背景

我最近发现了Python with关键字并开始看到它的潜在用处,可以更好地处理我以前使用过try: ... finally: ...构造的一些场景.我立即决定在我编写的一些代码中尝试使用MySQLdb连接对象.

我没有理会读取Python数据库API的实现者的方式__enter____exit__行为,并天真地期望行为与文件对象的行为一样 - 我所期待的只是退出调用connection.close().

想象一下,在这种行为中我的困惑:

>>> with util.get_db_connection() as conn:
...     print conn
... 
<MySQLdb.cursors.Cursor object at 0xb6ca8b4c>
Run Code Online (Sandbox Code Playgroud)

get_db_connection()返回一个MySQLdb连接对象,但该连接对象的__enter__方法返回一个游标对象,而不是连接对象本身,就像我期望给出文件对象的方式__enter____exit__工作方式一样.我想我应该做with util.get_db_connection() as cursor:,或者根本不用with.

问题

这个发现立刻让我想到了一些事情:

  1. 还有什么做的__enter____exit__MySQLdb的连接对象的方法吗?__exit__如果没有我明确要求发生这种变化,我是否会为我神奇地提交或回滚更改?还有什么不明显的我应该知道的吗?
  2. 这种行为在Python数据库API的其他实现者中是否相同(如sqlite3,django或psycopg2)?
  3. 这种行为是否在任何地方正式推出?针对'enter','exit'和'context manager' ctrl-f的最新规范(PEP 249 - Python数据库API规范v2.0)不会抛出任何东西.

Mar*_*ers 16

在将上下文管理器添加到Python语言之前,Python DBAPI编写得很好.

因此,不同的数据库库就如何实现上下文管理器支持(如果他们实现它)做出了自己的决定.

通常使用数据库作为上下文管理器将您与事务联系起来.交易开始__enter__,提交或中止__exit__,取决于是否存在例外情况.因此,在单独连接之后,您应该使用MySQL连接作为上下文管理器:

connection = util.get_db_connection()

with connection as cursor:
    cursor.execute(...)

# connection commit is issued if no exceptions were raised.
Run Code Online (Sandbox Code Playgroud)

sqlite3上下文管理器实现是微妙的不同; 它还管理事务,但不从__enter__方法返回游标:

con = sqlite3.connect(":memory:")
with con:
    cursor = con.cursor()
    # or use the connection directly
    con.execute(...)
Run Code Online (Sandbox Code Playgroud)

从技术上讲,它只是返回self__enter__.