対象読者
- pythonのwith構文の使い道がファイルオープン・クローズしか思い浮かばない人
結論
with構文はファイルオープン・クローズ以外にも、対となる処理を視覚的に分かりやすく、かつ簡潔に書くことができる。以下に例を挙げる。
- クラスのプロパティ値を変更・元に戻す
- ディレクトリの移動・元のディレクトリに戻る
根拠
with構文を用いたコードの方が長くなってしまっているが、クラスや関数の定義を別ファイルにしてある、と思って欲しい。
1.クラスのプロパティ値を変更・元に戻す例
matplotlibでの描画において、2種類のmarkerを使い分けたいとする。
通常のクラスを用いない場合、この処理は簡単で、以下のようにすればよい。しかし、このように処理をベタ書きしていては、コードを再利用したり、保守したりすることが難しく、使い捨てのコードしか作成することはできない。
import matplotlib.pyplot as plt
x = ...
data1 = ...
data2 = ...
data3 = ...
data4 = ...
plt.scatter(x, data1, marker="x")
plt.scatter(x, data2, marker="*")
plt.scatter(x, data3, marker="x")
plt.scatter(x, data4, marker="*")
plt.show()
そこでmatplotlibを隠蔽した便利な描画用クラスVisualizerがあるとする。クラス内にmarkerを変更するためのフラグを保持することで、markerを変更した描画を実現する。
import matplotlib.pyplot as plt
import contextlib
class Visualizer:
def __init__(self):
self._marker = "x"
def visualize(self, x, y):
plt.scatter(x, y, marker=self._marker)
@contextlib.contextmanager
def aster_context(self):
old = self._marker
self._marker = "*"
try:
yield
finally:
self._marker = old
...
vis = Visualizer()
vis.viusalize(x, data1) # marker = "x" として描画
with vis.aster_context():
vis.visualize(x, data2) # marker = "*" として描画
vis.viusalize(x, data3) # marker = "x" として描画
with vis.aster_context():
vis.visualize(x, data4) # marker = "*" として描画
...
2.ディレクトリの移動・元のディレクトリに戻る例
ディレクトリを移動して処理を行い、元のディレクトリに戻って別の処理を行うとする。with構文を用いない場合、以下のように書く。
import os
current = os.getcwd()
os.chdir(path1)
# 処理1
os.chdir(current)
# 処理2
...
with構文を使って書く場合は以下のようになる。with構文内のインデントでは別のディレクトリにいる、というコンテクストが視覚的に分かり、理解しやすい。まさにcontextmanager!
import contextlib
import os
@contextlib.contextmanager
def chdir(path):
current = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(current)
with chdir(path1):
# 処理1 path1のディレクトリにいる!
# 処理2
参考
オープンソースのAI用フレームワークchainer[Preferred Networks]
私は業務でchainerを用いてコーディングを行ってきた。他人の優れたコードに触れることで、私のプログラミングスキルは向上したように思う。
コメント