朝はバナナとヨーグルト

毎日同じ朝食でも大丈夫なタイプ

【Python】operatorの勉強(1)

PythonGetterSetter必要…?

まだまだペーペーです。プログラムだけでなく、文章に間違いや語弊がありましたらコメントなどで厳しく教えていただけたら幸いです。

きっかけ

他学科の友人の研究室に呼ばれ、プログラムを見て欲しいと頼まれた。

私「Pythonやってんだね」

友「なんもわからんけどね、卒論やばいから書いて欲しい」

私「おおん…頑張る…」

そんなこんなで、友人のプログラムを開発することになった私。

教授が書いてくれたという原型のプログラムを見ると、ものすごいJavaライクなプログラムが…

私「セッターとかゲッターって、Pythonだと意味なくね?」

友「なにそれおいしいの?」

私「おう…」

とはいったものの、これまで属性に直で値を代入していた自分。 「Javaみたいに、予期せぬ入力に対する処理とかどうすんだ?」と思ったので、調べてみた。

そして、自分の無知を知り恥じるのであった…

カプセル化

Pythonpublicとかprivateを見たことがなかったので、カプセル化とかないと思っていた。

でもpropertyってのがあるらしい。Google Style Guideに載っていたコードを引用したものが以下の通り。

import math


class Square:
    def __init__(self, side: int):
        self.side = side

    @property
    def area(self):
        return self._get_area()

    def _get_area(self):
        return self.side ** 2

    @area.setter
    def area(self, area):
        self._set_area(area)

    def _set_area(self, area):
        self.side = int(math.sqrt(area))

    @property
    def perimeter(self):
        return self.side * 4


def main():
    s1 = Square(3)
    print(s1.side, s1.area, s1.perimeter) # 3 9 12
    s1.area = 25
    print(s1.side, s1.area, s1.perimeter) # 5 25 20
    s1.perimeter = 10 # Attribute Error


if __name__ == '__main__':
    main()

このコードを噛み砕いて説明するとSquareクラスには属性が3つある。それは

  • side(直接読み書きできる)
  • area(メソッドを介して読み書きできる)
  • perimeter(メソッドを介して、読みだけできる)

プロパティと関数の頭につけるだけで、属性のようにアクセスできる。

@area.setterだけでなく、@area.getterもあるが@propertyと動作は同じ。@propertyのみを設定すると、値の書き込みができなくなり、実質読み取り専用の属性を作ることができる。

感想

意図しない値の代入をdefの中で防ぐことができる。(たとえば、areaに負の値が入ったらエラー表示とか)

研究で使うプログラムでそこまでの配慮は求められないが、今後書くプログラムには採用していきたい。

あんまり多用するとコードが読みづらくなりそうだし、使い方をよく考えないとな…