pymc4のソースコード読んでみた - “Context”, Initial Model Class, sampling and random variable [aafa32d]
コミット
2018/05/30のコミットです。
Initial Model Class, sampling and random variable · pymc-devs/pymc4@aafa32d · GitHub
主に、pymc4の根幹となる Model
と RandomVariable
クラスが作成されています。
以下ファイルが追加されています。
- .vscode/settings.json
- pymc4/init.json
- pymc4/model.py
- pymc4/random_variable.py
- pymc4/sample.py
- test.ipynb
一つ一つを細かくみたいので、今回は model.py
の Context
クラスだけを見てみます。
model.py
以下の5つが主に記述されています(以前のコミットと類似の情報は省略します)
- Contextクラスの作成 <- 今回はContextクラスのコードを読みます
- dictクラスを継承したtreedictクラスの作成
- withparentというhelperメソッドの作成
- Contextクラスを継承したModelクラスの作成
- modelcontextメソッドの作成
- plotメソッドの作成(おそらく動作確認テスト用)
class Context(object): """Functionality for objects that put themselves in a context using the `with` statement. """ contexts = threading.local() def __enter__(self): type(self).get_contexts().append(self) return self def __exit__(self, typ, value, traceback): type(self).get_contexts().pop()
上記のコードで行われているのは3つのことだけです。
threading.local()
でcontexts
を作成__enter__
メソッドを定義__exit__
メソッドを定義
threading.local() で contexts を作成
スレッド毎に異なるローカル変数を保持できるストレージみたいなものみたいです。
例えば以下の疑似コードでは、スレッド毎にランダムな数を生成していますがスレッド毎に出力がことなっていることがわかります。
(他メソッドは省略) def f(d): d.val = random.randint(1, 100) <- Thread-1 と Thread-2 ではそれぞれ乱数を生成 show(d) if __name__ == '__main__': d = threading.local() show(d) d.val = 999 <- メインスレッドの値 show(d) for i in range(2): t = threading.Thread(target=f, args=(d,)) t.start()
出力: ↓ それぞれのスレッドで値が異なる
(MainThread) value=999 (Thread-1) value=51 (Thread-2) value=19
see: Python Multithreading Tutorial: threading.local() - 2018
enter + exit メソッドを定義
__enter__
と __exit__
メソッドをクラスに定義することで、withステートメントが使えます。
例えば以下のようなサンプルコードを書いてみます。
class Sample(object): def __init__(self): print("initialized") def __enter__(self): print("entered") return self def __exit__(self, typ, value, traceback): print("end")
- 初期化の動作確認
出力: __init__
のみが呼ばれるため、以下の通り initialized
だけが表示されます。
s = Sample() # (出力) # initialized
- withを使った場合の動作確認
以下の順番で各処理が走るようです。
__init__
処理が走って、initialized
が表示される- with文に入った瞬間に
__enter__
メソッドが処理され、変数s
にインスタンスが束縛される - with文内の
print(s)
でs
インスタンスの内容が表示される - with文を出た直後に
__exit__
メソッドが処理され、end
が表示される
with Sample() as s: print(s) # (出力) # initialized # entered # <__main__.Sample object at 0x126fb1208> # end
see: Understanding Python’s “with” statement