Python - クラス - プロパティ

公開日:2019-03-04 / 更新日:2019-03-13

1. 概要

プロパティ(クラスのデータ)の使い方です。

2.1 サンプル

クラスに speed と言うプロパティを定義して、クラスの利用者側から値の設定と取得を行っています。

ソース
class Car:

    def __init__(self):
        self.speed = 0

car = Car()
print( car.speed )
car.speed = 100
print( car.speed )

実行結果
0
100

2.2 メソッドからプロパティを使う

同じクラスのメソッドからプロパティを参照する場合は、メソッドの第1引数の self を使います。
self は自動的に渡されるため、メソッドの呼び出し側での指定は不要です。
self を付けないと、メソッド内のローカル変数扱いとなり、メソッドから抜けると破棄されます。

ソース
class Car:

    def __init__(self):
        self.speed = 0
        
    def speed_up(self):
        self.speed += 10

car = Car()
car.speed_up()
car.speed_up()
car.speed_up()

print( car.speed )

実行結果
30

2.3 プロパティの動的追加

クラスの利用者側からプロパティの追加をしています。
インスタンスに関する追加情報を、元のクラスを変更せずに付与できます。

動的に外部から追加されるプロパティは、基本的にはクラス側では知りえないため、
クラス側からは使用しないプロパティになります。
ソース
class Car:
    pass

car = Car()
car.note = "フェラーリ"

car2 = Car()
car2.note = "ポルシェ"

carList = [car, car2]

for c in [car, car2]:
    print( c.note )

実行結果
フェラーリ
ポルシェ

2.4 読み取り専用プロパティ

メソッドの前に @property を付けると、メソッドをプロパティのように、()を付けずに使用することができます。

クラス内の変数を直接公開した場合との違い
・読み取り専用にできる。
・プロパティの値が取得される際に、処理を実行することができる。

ソース
class Car:

    def __init__(self):
      self._speed = 100

    @property
    def speed(self):
        return self._speed

car = Car()
print(car.speed)

#エラー。設定はできない。
#car.speed = 150

実行結果
100

2.5 書き込み可のプロパティ

メソッドの前に @プロパティ名.setter を付けると、書き込み可のプロパティになります。
読み取り専用プロパティと書き方が異なるため要注意。
プロパティに代入された値は、setter を付けたメソッドの2番目の引数で取得できます。

ソース
class Car:
    
    def __init__(self):
      self._speed = 100
    
    @property
    def speed(self):
        print("speed の取得")
        return self._speed

    @speed.setter
    def speed(self, value):
        print("speed の設定")
        self._speed = value

car = Car()
print(car.speed)

car.speed = 200
print(car.speed)

実行結果
speed の取得
100
speed の設定
speed の取得
200

2.6 property() を使ったプロパティの定義

property()を使うと、@property や @プロパティ名.setter を使わずにプロパティを定義できます。
定義方法は、getter、setter に該当するメソッドを、property() に渡して、プロパティの変数に設定するだけです。
getter、setter よりも下に定義する必要があるので要注意。
以下では setter も設定していますが、getter だけにすることもできます。
ソース
class Car:
    
    def __init__(self):
      self._speed = 100
    
    def get_speed(self):
        print("speed の取得")
        return self._speed

    def set_speed(self, value):
        print("speed の設定")
        self._speed = value

    speed = property(get_speed, set_speed)


car = Car()
print(car.speed)

car.speed = 200
print(car.speed)

実行結果
speed の取得
100
speed の設定
speed の取得
200

2.7 privateプロパティ(プロパティの隠蔽)

Python にはアクセス修飾子(public, private)がありません。
外部から隠蔽したい場合には、変数名の先頭に __ を付けます。
但し、これでも完全ではなく、「_クラス名__プロパティ名」と言う名前で外部からアクセスできます。
dir() で名前の確認ができます(dir はディレクトリとは関係ありません)

また慣例で、変数名の先頭に _ を付けて、private である意志表示をします。
あくまでも意志表示のため、そのまま外部からアクセス可能です。
ソース
class Car:

    def __init__(self):
      self.__speed = 100



car = Car()

#エラー。AttributeError
#print(car.__speed)

#オブジェクトのメンバリストの表示
print(dir(car))

#隠蔽されたプロパティの取得
print(car._Car__speed)
car._Car__speed = 200

実行結果
['_Car__speed', '__class__', '__delattr__', '__dict__', '__dir__', 
 '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
 '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', 
 '__lt__', '__module__', '__ne__', '__new__', '__reduce__', 
 '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
 '__subclasshook__', '__weakref__']
100