Pythonのpropertyでちょっとハマった
ハマったこと
クラスのインスタンス作成時にpropertyのsetterがうまく呼び出されない。
原因
クラスのinitで直接変数に値を代入していた
Propertyとは
Pythonでは変数のgetter・setterを簡便に設定できるpropertyという組み込み関数が有る。 他言語にあるgetNum()やsetNum()のような書き方をする必要がなく、 インスタンス変数へのアクセスをドット記法で行うことができるためコードがシンプルになる。
sample.py
class Example: def __init__(self, num): self._num = num @property def num(self): return self._num @num.setter def num(self, value): # 0以下だと例外 if value <= 0: raise ValueError('num must be over 0!') self._num = value
上記のクラスを対話モードで使ってみる。
対話モード
>>> from sample import Example >>> example = Example(10) >>> example.num 10 >>> example.num = 1 >>> example.num 1 >>> example.num = 0 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "sample.py", line 12, in num raise ValueError("num must be over 0!") ValueError: num must be over 0! >>>
ただし、上記のコードではinit内で直接変数に値を代入しているため インスタンス作成時にはsetterが動作しない。
対話モード
>>> from sample import Example >>> example = Example(0) >>> example.num >>> 0
そのためインスタンス作成時にsetterを動作させるには init内でsetterを呼び出す必要がある。
sample.py
class Example: def __init__(self, num): # self._num = num # setterを呼び出す self.num = num @property def num(self): return self._num @num.setter def num(self, value): if value <= 0: raise ValueError('num must be over 0!') self._num = value
同様に対話モードで使ってみる。 先ほどの例とは違い、インスタンス作成時にsetterが動作し 例外が投げられている。
対話モード
>>> from sample import Example >>> example = Example(0) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "sample.py", line 3, in __init__ self.num = num File "sample.py", line 12, in num raise ValueError("num must be over 0!") ValueError: num must be over 0! >>>