LoginSignup
0
1

More than 3 years have passed since last update.

python オブジェクトとクラスについて

Last updated at Posted at 2020-03-23

自作でMTVモデルを作成する際に、クラスの扱い方について
学んだ為、メモとして残します。

内容は初歩中の初歩な内容です。
学んだことは、随時更新します。

クラスの定義

sample.py
class Person(object):
    def eat(self):
        print('eat')

person = Person()
person.eat()
出力結果
eat

引数のobjectは無くても良いが、python2系の名残で(コードスタイルとしては)記載している方が良いとのこと。
person = Person()でクラスの呼出が可能。

コンストラクタとデストラクタ

sample.py
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は他のメソッドからも呼出ができる。

クラスの継承

sample.py
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による親のメソッド呼出

sample.py
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)

sample.py
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つをつける手法などもあるが、親クラスと子クラスで
メソッド名が重複した時に、コンフリクトを避ける目的で使ったりするのが一般的とのこと。
詳細はこちらで確認してください。

クラス変数

sample.py
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__メソッド内に変数を持っていき、
オブジェクトが生成される度に、変数の初期化処理を記載するなどして対応する必要がある。

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1