12

バックグラウンド

私は最近、Pythonwithキーワードを発見し、以前は構文を使用していたいくつかのシナリオをより適切に処理するための潜在的な有用性を見始めましtry: ... finally: ...た。私はすぐに、書いていたコードの MySQLdb 接続オブジェクトで試してみることにしました。

__enter__私は、Python データベース API の実装者がどのように振る舞い、どのように振る舞うかについてわざわざ調べたりはしませんでした__exit__。その振る舞いがファイル オブジェクトの振る舞いと似ていることを素朴に期待していましたconnection.close()

次に、この動作での私の混乱を想像してください。

>>> with util.get_db_connection() as conn:
...     print conn
... 
<MySQLdb.cursors.Cursor object at 0xb6ca8b4c>

get_db_connection()はMySQLdb接続オブジェクトを返しますが、その接続オブジェクトのメソッドは、ファイルオブジェクトに対してどのように機能__enter__するかを期待していたような接続オブジェクト自体ではなく、カーソルオブジェクトを返します。私はやるべきだと思います。そうでなければ、まったく使用しないでください。__enter____exit__with util.get_db_connection() as cursor:with

質問

この発見はすぐに私にいくつかのことを疑問に思います:

  1. __enter__MySQLdb 接続オブジェクトのおよびメソッドは他に何__exit__をしますか? __exit__明示的に要求しなくても、魔法のように変更をコミットまたはロールバックするつもりですか? 私が知っておくべき明らかでないことは他にありますか?
  2. この動作は、Python データベース API の他の実装者 (sqlite3、django、または psycopg2 など) でも同じですか?
  3. この動作は正式にどこかで仕様されていますか? ctrl-f'enter'、'exit'、'context manager'の最新の仕様 ( PEP 249 -- Python Database API Specification v2.0 ) を使用しても、何もスローされません。
4

2 に答える 2

20

Python DBAPI は、コンテキスト マネージャーが Python 言語に追加される前に作成されました。

そのため、さまざまなデータベース ライブラリが、コンテキスト マネージャーのサポートを実装する方法について独自の決定を下しました (実装したとしても)。

通常、データベースをコンテキスト マネージャーとして使用すると、トランザクションに結び付けられます。トランザクションは に開始され、例外があったかどうかに応じて に__enter__コミットまたは中止されます。__exit__そのため、個別に接続した後、MySQL 接続をコンテキスト マネージャーとして使用することになっています。

connection = util.get_db_connection()

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

# connection commit is issued if no exceptions were raised.

sqlite3コンテキスト マネージャーの実装は微妙に異なります。トランザクションも管理しますが、__enter__メソッドからカーソルを返しません。

con = sqlite3.connect(":memory:")
with con:
    cursor = con.cursor()
    # or use the connection directly
    con.execute(...)

技術的には、 に戻るだけselfです__enter__

于 2013-03-22T10:38:43.977 に答える