自作でMTVモデルを作成する際に、クラスの扱い方について
学んだ為、メモとして残します。
内容は初歩中の初歩な内容です。
学んだことは、随時更新します。
クラスの定義
class Person(object):
def eat(self):
print('eat')
person = Person()
person.eat()
eat
引数のobjectは無くても良いが、python2系の名残で(コードスタイルとしては)記載している方が良いとのこと。
person = Person()
でクラスの呼出が可能。
コンストラクタとデストラクタ
class Person(object):
"""コンストラクタ"""
def __init__(self, food):
self.food = food
print('Food is ready')
def eat(self):
print('eat {}'.format(self.food))
"""デストラクタ"""
def __del__(self):
print('Thanks for the food')
person = Person('apple')
person.eat()
del person # 明示的に記述することもできる
Food is ready
eat apple
Thanks for the food
コンストラクタとは、オブジェクトを作る際に最初に呼出されるもの。
反対にデストラクタとは、オブジェクトがなくなる際に呼出されるもの。
コンストラクタの__init__
メソッドは一番最初に呼ばれる為、初期設定等を記述する場合に用いられる。
他にも__new__
メソッドなどがある。
self.food
は他のメソッドからも呼出ができる。
クラスの継承
class Animal(object):
def eat(self):
print('eat')
class Monkey(Animal):
def eat(self, food):
self.food = food
print('eat {}'.format(self.food))
class Cheetah(Animal):
def run(self):
print('run')
animal = Animal()
animal.eat()
print('###########')
monkey = Monkey()
monkey.eat('banana') # メソッドのオーバーライド
print('###########')
cheetah = Cheetah()
cheetah.eat() # クラスの継承
cheetah.run() # 機能の拡張
eat
###########
eat banana
###########
eat
run
親クラスを子クラスの引数に渡せば、親クラスの機能を使うことができる。
親クラスの機能をある場合の時だけに拡張したい場合などに使える。
関数を子クラスで上書きすることもできる。
superによる親のメソッド呼出
class Animal(object):
def __init__(self, food=None):
self.food = food
def eat(self):
print('eat')
class Monkey(Animal):
def __init__(self, food):
super().__init__(food)
def eat(self):
print('eat {}'.format(self.food))
animal = Animal()
animal.eat()
print('###########')
monkey = Monkey('banana')
monkey.eat()
eat
###########
eat banana
super()
で親クラスの__init__関数が呼ばれた上で、
子クラスの__init__関数が実行される。
プロパティ(getter/setter)
class Animal(object):
def __init__(self, food=None, password=None):
self._food = food
self.password = password
"""getter"""
@property
def food(self):
return self._food
"""setter"""
@food.setter
def food(self, food):
if self.password == 'pass':
self._food = food
else:
# raise ValueError
print("エラー") # 確認用
animal = Animal('banana', password='pass')
print(animal.food)
animal.food = "orange"
print(animal.food)
print("##############")
animal2 = Animal('banana')
print(animal2.food)
animal2.food = "orange"
print(animal2.food)
banana
orange
##############
banana
エラー
プロパティを用いることで、外部から上書きされたくない変数に読み込みはできるが
値を書き換えてほしくないよという時に明示的に表すことができるとされている。
第三者が、設計者の意図しない操作をしてエラーが発生してしまうような事態を防ぐことができる。
_変数名
アンダースコアをつけることで、
外部から見えてないていにする意味があるとされている。
実際に動作にはほとんど影響しないので、変数の直接参照はできる。
ゲッターは@property
を追記し関数名を対象の変数名にする。
セッターはプロパティーを設定してる関数名に.setter
で設定可能。
ある条件下でのみ上書きしてもいいとする場合に用いるとさらている。
__変数名
アンダースコア2つをつける手法などもあるが、親クラスと子クラスで
メソッド名が重複した時に、コンフリクトを避ける目的で使ったりするのが一般的とのこと。
詳細はこちらで確認してください。
クラス変数
class Person(object):
eated_list = [] # クラス変数
def eat(self, food):
print('eat {}'.format(food))
self.eated_list.append(food)
personA = Person()
personA.eat("apple")
print(personA.eated_list)
personB = Person()
personB.eat("orange")
print(personB.eated_list)
eat apple
['apple']
eat orange
['apple', 'orange']
クラス変数とは全ての生成されるオブジェクトで共有可能な変数。
その為、オブジェクト同士で共有したくない情報も上記のコードの様に共有してしまうリスクがある。
これを回避するには、__init__
メソッド内に変数を持っていき、
オブジェクトが生成される度に、変数の初期化処理を記載するなどして対応する必要がある。