pythonのwith構文のopen/close以外の使い方

スポンサーリンク

対象読者

  • pythonのwith構文の使い道がファイルオープン・クローズしか思い浮かばない人

結論

with構文はファイルオープン・クローズ以外にも、対となる処理を視覚的に分かりやすく、かつ簡潔に書くことができる。以下に例を挙げる。

  1. クラスのプロパティ値を変更・元に戻す
  2. ディレクトリの移動・元のディレクトリに戻る

根拠

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を用いてコーディングを行ってきた。他人の優れたコードに触れることで、私のプログラミングスキルは向上したように思う。

コメント

タイトルとURLをコピーしました