『Effective Python』の続き。ゲッターやセッターをPythonで実装しちゃうのは素人。 www.effectivepython.com
今回からChapter 4「メタクラスと属性」に突入。 タイトルの順序はメタクラスが先であるが、しばらくは属性の話が続く。
ゲッターやセッターと聞くとJavaが思い浮かぶが、PythonではJavaのようにゲッターやセッターを実装する必要なはい。
class OldResistor(object): def __init__(self, ohms): self._ohms = ohms def get_ohms(self): return self._ohms def set_ohms(self, ohms): self._ohms = ohms r0 = OldResistor(50e3) print('Before: %5r' % r0.get_ohms()) r0.set_ohms(10e3) print('After: %5r' % r0.get_ohms())
とやっても問題ないが、
r0.set_ohms(r0.get_ohms() + 5e3)
というアレなコードが出来てしまう。
Pythonの場合はシンプルに
class Resistor(object): def __init__(self, ohms): self.ohms = ohms self.voltage = 0 self.current = 0 r1 = Resistor(50e3) r1.ohms = 10e3
とすれば、
r1.ohms += 5e3
とできる。
ここまでではタイトオンリーな話題であるが、より複雑なことを行いたい場合は@property
デコレータを使いましょう、と述べている。
例えば、電圧値をセットすると電流値を更新するようにできる。
class VoltageResistance(Resistor): def __init__(self, ohms): super().__init__(ohms) self._voltage = 0 @property def voltage(self): return self._voltage @voltage.setter def voltage(self, voltage): self._voltage = voltage self.current = self._voltage / self.ohms r2 = VoltageResistance(1e3) print('Before: %5r amps' % r2.current) r2.voltage = 10 print('After: %5r amps' % r2.current)
>>> Before: 0 amps After: 0.01 amps
注意点は色々書いてあるが、雑に要約するならば「余計なことはするな」と言えるだろうか。 上記のように抵抗値と電圧値が決まっている状態で電流値が更新される、ならばまだ想定できるが、
class MysteriousResistor(Resistor): @property def ohms(self): self.voltage = self._ohms * self.current return self._ohms @ohms.setter def ohms(self, ohms): self._ohms = ohms r7 = MysteriousResistor(10) r7.current = 0.01 print('Before: %5r' % r7.voltage) r7.ohms print('After: %5r' % r7.voltage)
と余計なことをすると
>>> Before: 0 After: 0.1
のようにr7.ohm
を呼び出しただけで電圧値が変わってしまう。