前提
以下のような方を前提に書いています。
- Pythonのwith文は何となくわかる
- ibisを使ったことがある
環境
大きく違わなければ使えると思います。
python: 3.12(3.8以降推奨)
ibis: 11.x(v9.0.0以降であればdisconnect()が使用可能)
Ibisでwith文を使いたい理由
仕事柄、jupyter notebookをよく使うのですが、接続した後に色々分析をして時間が経ち、切断を忘れることが多々発生し、どうにかならんかなと思っていました。
「忘れるならwith文を使って安全に接続・切断をすればいいじゃない」ということで調べたら、ibisにはコンテキストマネジャーがネイティブ実装されていないっぽいです。
「でも使いたい!」ということで自作します。
自作コンテキストマネージャーの実装
v10.0.0のリリースノートに以下のような言及があるため、contextlibを使用して自作します。
- config:
option_contextis removed. Usecontextlib.contextmanagerto create your own version of this functionality if necessary.
実装はこちらの記事を参考にしました。
from contextlib import contextmanager
import ibis
@contextmanager
def ibis_connection(url, **kwargs):
"""Ibis接続をコンテキストマネージャーとして扱う
使用例:
with ibis_connection('duckdb://') as con:
table = con.table('my_table')
result = table.execute()
"""
con = ibis.connect(url, **kwargs)
try:
yield con
finally:
con.disconnect()
これを使うと以下のようにbefore-afterされます。
これで切断忘れもなくなり、可読性も向上します。
before:
try:
con = ibis.connect("your_url")
table = con.table("table_name")
# 他の処理
finally:
con.disconnect()
after:
with ibis_connection("your_url") as con:
table = con.table("table_name")
# 他の処理
なぜネイティブ実装されていないのか?
ただ、なぜネイティブ実装されていないのか?が疑問に残ります。
データベースを扱うライブラリの多くが、コンテキストマネジャーをサポートしていて、with文を使った書き方を推奨しています。
では、なぜibisには無いのかを自分なりに考えてみました。
結論、「ibisは接続の長期保持と遅延実行を前提としているから」 だと思います。
ibisは分析ワークフローでの使用を想定しており、以下の特徴があります:
- 一度接続したら、複数のクエリを実行することが一般的
- 式の構築(table.mutate()など)と実行(execute())が分離されている
そのため、with文のような短命な接続管理よりも、接続を長期間保持して使い回す設計が優先されているのだと考えられます。
実際、以下のようにwith文の外でexecute()を呼び出すと、「接続はすでに閉じたよ!」とエラーになります:
with ibis_connection("your_url") as con:
table = con.table("table_name")
# 命令の定義
table = table.mutate(c=_.a+_.b)
# with文を抜けた後
df = table.execute()
# Connection Error: Connection already closed!
with文の中でexecute()を呼び出し、DataFrameにしてしまえばエラーは出ませんが、そういった接続のスコープが狭い使い方はibisの思想に合わないのかなと思ってます。
まだまだ初心者なので、ご意見等があればコメントください!