pymc4のソースコード読んでみた - “withparent”, 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
前回飛ばした withparent
のところを継続して読んでみます。
withparent - model.py
withparent
メソッドは以下の treedict
クラスの内部で呼ばれています(メソッド内ではなく単体で呼ばれています)
親の dict
クラスの __setitem__
と update
メソッドを上書きしているように見えます。 withparent
という名前からすると、値のセット・更新時に parent
の値も拡張するようにしていると推測できます。
# typechecking here works bad __setitem__ = withparent(dict.__setitem__) update = withparent(dict.update)
実際に withparent
メソッドを読んでみます。
def withparent(meth): """Helper wrapper that passes calls to parent's instance""" def wrapped(self, *args, **kwargs): res = meth(self, *args, **kwargs) if getattr(self, 'parent', None) is not None: getattr(self.parent, meth.__name__)(*args, **kwargs) return res # Unfortunately functools wrapper fails # when decorating built-in methods so we # need to fix that improper behaviour wrapped.__name__ = meth.__name__ return wrapped
コメントに Helper wrapper that passes calls to parent's instance
とあるように、 parent
のインスタンスを呼ぶヘルパーメソッドのようです。このあたりは以前に読んだ tree_contains
と似たようなものだと思えます。
withparent
内の以下の wrapped
メソッドが定義されているのでまずはこちらを読みます。 meth
は withparent
から渡ってきた引数の dict.__setitem__
か dict.update
になります。
def wrapped(self, *args, **kwargs): res = meth(self, *args, **kwargs) if getattr(self, 'parent', None) is not None: getattr(self.parent, meth.__name__)(*args, **kwargs) return res
以下の処理では meth
が dict.__setitem__
と同等だとすると、単に self.__setitem__
を呼んでいるのと一緒のはずです。
res = meth(self, *args, **kwargs)
その後に tree_contains
と同様に、 parent
の有無をチェックしてもし存在するなら parent
の __setitem__
を呼び出しています。
if getattr(self, 'parent', None) is not None: getattr(self.parent, meth.__name__)(*args, **kwargs)
最後に wrapped
メソッドの __name__
を上書きしています。以下のように試しに名前変更前後の値を見てみると、もともと wrapped
という名前が __setitem__
という名前に変更されていることがわかります。
print(wrapped.__name__) # <= wrapped wrapped.__name__ = meth.__name__ print(wrapped.__name__) # <= __setitem__ return wrapped
ちなみに def __setitem__
と def update
を単に treedict
クラス内で作成して、親の dict
クラスの処理を上書きしても同様のことができるはずです。