LoginSignup
7
5

More than 5 years have passed since last update.

PythonでClassのメンバ変数が更新されたのを確認する

Posted at

はじめに

PythonでClassのメンバ変数(アトリビュート)の値が不意に書き換わっていて困ったときに調べた内容のメモです.(既存のコードでClassのメンバ変数が外から直接書き換えられてるっぽい!?みたいなしんどい状況)

プロパティに変更する

ぱっと思いつくのはプロパティを用意することですね.あまりPythonで書いたことがなかったのと,プロパティの書き方が何種類かあっていつも調べてしまうので,簡単にまとめておきます.
ここではデコレータを使った書き方を載せておきます.

spam.py
class Spam():
    def __init__(self, value):
        self._value = value

    @property
    def value(self):
        print(f'Get Value: {self._value}')
        return self._value

    @value.setter
    def value(self, value):
        self._value = value
        print(f'Set Value: {self._value}')

def main():
    spam = Spam(42)
    print(spam.value)
    spam.value = 23
    print(spam.value)

if __name__ == "__main__":
    main()
実行結果
$ python spam.py
Get Value: 42
42
Set Value: 23
Get Value: 23
23

setter,getterメソッドを用意してproperty関数で登録する書き方もありますが,デコレータを使った方法のほうがシンプルかと思います.また読み取り専用のプロパティにしておきたい場合は,setterを用意する必要はありません.
外部からClassのメンバ変数を直接書き換えるようなコードになっていても,同名のプロパティを用意すれば呼び出し側のコードを変更せずに今回のようなログを追加することができそうです.

__setattr__をオーバーライド

ざっとメンバ変数の更新を確認したいだけなら,__setattr__という特殊メソッドを使う方法もあります.
spam.value = 23みたいなコードを書くと,内部で__setattr__が呼ばれているため,このメソッドをオーバーライドすることでロギング処理などを差し込めます.

spam.py
class Spam():
    def __init__(self, value):
        self.value = value

    def __setattr__(self, name, value):
        print(f'Set {name}: {value}')
        object.__setattr__(self, name, value)

def main():
    spam = Spam(42)
    print(spam.value)
    spam.value = 23
    print(spam.value)

if __name__ == "__main__":
    main()
実行結果
$ python spam.py
Set value: 42
42
Set value: 23
23

注意点は__setattr__の中で基底クラス(明示的に継承していなければobject)の__setattr__を呼び出さないと値がセットされなくなります.
確認をしたいメンバ変数が複数ある場合でも__setattr__をひとつ実装するだけで済みますし,逆に特定のメンバ変数だけ確認を取りたい場合は引数で渡ってくるnameを見てロギング処理を分岐させるとよいです.

おわりに

普段の単純なコードではあまり__setattr__なんかを触る機会は少ないかもですが,知っておくと何かのときに便利ですね.

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5