__enter__ 和 __exit__ 是 Python 数据库 API 中指定的连接对象的行为吗? [英] Is __enter__ and __exit__ behaviour for connection objects specified in the Python database API?
问题描述
背景
我最近发现了 Python with
关键字,并开始看到它的潜在用途,可以更漂亮地处理一些我以前使用过的场景 try: ... finally: ...
构造.我立即决定在我正在编写的一些代码中在 MySQLdb 连接对象上试用它.
我没有费心去阅读 __enter__
和 __exit__
在 Python 数据库 API 的实现者中的行为方式,并且天真地期望行为与文件对象的行为类似- 我所期望的只是退出调用 connection.close()
.
想象一下我对这种行为的困惑:
<预><代码>>>>使用 util.get_db_connection() 作为连接:...打印连接...<MySQLdb.cursors.Cursor 对象在 0xb6ca8b4c>get_db_connection()
返回一个 MySQLdb 连接对象,但该连接对象的 __enter__
方法返回一个游标对象,而不是我期望的连接对象本身__enter__
和 __exit__
适用于文件对象.我想我应该使用 util.get_db_connection() 作为游标:,或者根本不使用 with
.
问题
这个发现立刻让我想知道一些事情:
- MySQLdb 连接对象的
__enter__
和__exit__
方法还有什么作用?__exit__
是否会在没有我明确要求发生的情况下神奇地为我提交或回滚更改?还有什么我应该知道的非显而易见的事情吗? - 这种行为在 Python 数据库 API 的其他实现者(如 sqlite3、django 或 psycopg2)中是否相同?
- 这种行为是否正式规定在任何地方?
ctrl-f
使用最新规范(PEP 249 -- Python用于输入"、退出"和上下文管理器"的数据库 API 规范 v2.0) 不会抛出任何内容.
Python DBAPI 在上下文管理器被添加到 Python 语言之前就已经编写好了.
因此,不同的数据库库就如何实现上下文管理器支持做出了自己的决定(如果它们完全实现了).
通常将数据库用作上下文管理器会将您与事务联系起来.事务在 __enter__
上开始,并在 __exit__
上提交或中止,具体取决于是否有异常.因此,您应该在单独连接后使用 MySQL 连接作为上下文管理器:
connection = util.get_db_connection()以连接为游标:游标.执行(...)# 如果没有引发异常,则发出连接提交.
sqlite3
上下文管理器实现 略有不同;它还管理事务,但不从 __enter__
方法返回游标:
con = sqlite3.connect(":memory:")与骗局:游标 = con.cursor()# 或者直接使用连接执行(...)
从技术上讲,它只是在 __enter__
上返回 self
.
Background
I recently discovered the Python with
keyword and started seeing its potential usefulness for more prettily handling some scenarios where I'd previously have used try: ... finally: ...
constructs. I immediately decided to try it out on the MySQLdb connection object in some code I was writing.
I didn't bother reading up on how __enter__
and __exit__
behave in implementors of the Python database API, and naively expected the behaviour to be like that of file objects - all I was expecting was for exit to call connection.close()
.
Imagine my confusion, then, at this behaviour:
>>> with util.get_db_connection() as conn:
... print conn
...
<MySQLdb.cursors.Cursor object at 0xb6ca8b4c>
get_db_connection()
returns a MySQLdb connection object, but the __enter__
method of that connection object returns a cursor object, not the connection object itself like I was expecting given how __enter__
and __exit__
work for file objects. I guess I ought to be doing with util.get_db_connection() as cursor:
, or else not using with
at all.
Questions
Immediately this discovery makes me wonder a few things:
- What else do the
__enter__
and__exit__
methods of MySQLdb connection objects do? Is__exit__
going to magically commit or rollback changes for me without me explicitly asking for that to happen? Is there anything else non-obvious that I should know? - Is this behaviour the same in other implementers of the Python database API (like sqlite3, django, or psycopg2)?
- Is this behaviour formally specced anywhere?
ctrl-f
ing the latest spec (PEP 249 -- Python Database API Specification v2.0) for 'enter', 'exit' and 'context manager' doesn't throw up anything.
The Python DBAPI was written well before context managers were added to the Python language.
As such, different database libraries made their own decisions on how to implement context manager support (if they implemented it at all).
Usually using the database as a context manager ties you to a transaction. The transaction is started on __enter__
, and committed or aborted on __exit__
, depending on wether or not there was an exception. As such, you are supposed to use the MySQL connection as a context manager after connecting seperately:
connection = util.get_db_connection()
with connection as cursor:
cursor.execute(...)
# connection commit is issued if no exceptions were raised.
The sqlite3
context manager implementation is subtly different; it also manages transactions, but does not return a cursor from the __enter__
method:
con = sqlite3.connect(":memory:")
with con:
cursor = con.cursor()
# or use the connection directly
con.execute(...)
Technically, it just returns self
on __enter__
.
这篇关于__enter__ 和 __exit__ 是 Python 数据库 API 中指定的连接对象的行为吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!