数弱の文系大学生によるブログです。

Python、Webデザイン関連の記事を投稿していけたらなと思っています。

備忘録的なブログなので、読みにくい文章だと思います。ご了承ください。

Python3の復習(オブジェクトとクラス②-継承-)

こんにちは。

かにたまごです。
今日は復習メインでいこうと思っているので、記事多めです。たぶん。


今回は

  • オブジェクトとクラス(継承)

について、復習していきたいと思います。


今までのPython3 復習履歴は以下の通り。

  1. 数値・文字列
  2. リスト・タプル
  3. 辞書・集合
  4. if文・while文・for文
  5. 内包表記
  6. 関数
  7. ジェネレータ
  8. デコレータ
  9. 名前空間とスコープ
  10. アンダーバー・アンダースコアの意味
  11. エラー処理:try・except
  12. モジュール・パッケージ
  13. 標準ライブラリ
  14. オブジェクトとクラス①-クラスの定義-

オブジェクトとクラス②-継承-

継承は、既存のクラスを受け継ぎつつ、新しいコードを追加することができる機能。

既存クラスのコピペ+新規コードでも実現することは可能だが、それは同じコードが二つ存在していることになるので無駄。それに、メンテナンス作業が面倒になる。


新しく定義するクラスでは、追加・変更したい部分だけ定義すればよい。
継承元のクラス定義を上書きすることをオーバーライドと呼ぶ。

そして、この継承元のクラスをスーパークラス基底クラスと呼び、継承先のクラスをサブクラス派生クラスと呼ぶ。

呼び方色々ありすぎぃ( ^ω^)・・・

適切ではないであろう例を用いて書いてみる。

class Anime():
    def __init__(self, airtime):
        self.airtime = airtime

    def introduce(self):
        print("放送時間: {}分".format(self.airtime))

class Nitijo(Anime):
    pass

nitijo = Nitijo(30)
nitijo.introduce()
放送時間: 30分

継承先のクラスでメソッドを上書き(オーバーライド)してみる。

class Anime():
    def __init__(self, airtime):
        self.airtime = airtime

    def introduce(self):
        print("放送時間: {}分".format(self.airtime))

class Nitijo(Anime):
    def introduce(self):
        print("ジャンル: 日常\n放送時間: {}分".format(self.airtime))

nitijo = Nitijo(30)
nitijo.introduce()
ジャンル: 日常
放送時間: 30分

継承先にメソッドを追加して、個性を出す。

class Anime():
    def __init__(self, airtime):
        self.airtime = airtime

    def introduce(self):
        print("放送時間: {}分".format(self.airtime))

class Nitijo(Anime):
    def introduce(self):
        print("ジャンル: 日常\n放送時間: {}分".format(self.airtime))

    def honobono(self):
        print("ほのぼの系の日常アニメ")

class Battle(Anime):
    def introduce(self):
        print("ジャンル: バトル\n放送時間: {}分".format(self.airtime))

    def guro(self):
        print("グロ系のバトルアニメ")

nitijo = Nitijo(30)
nitijo.introduce()
nitijo.honobono()

battle = Battle(15)
battle.introduce()
battle.guro()
ジャンル: 日常
放送時間: 30分
ほのぼの系の日常アニメ

ジャンル: バトル
放送時間: 15分
グロ系のバトルアニメ

ここで、継承元のAnimeインスタンスでNitijoクラスやBattleクラスで定義されたメソッドにアクセスしようとすると、エラーが発生する。

anime = Anime(30)
anime.introduce()
anime.honobono()
放送時間: 30分
Traceback (most recent call last):
  File "blog_test.py", line 922, in <module>
    anime.honobono()
AttributeError: 'Anime' object has no attribute 'honobono'
  • 継承元のメソッドを呼び出すsuper()

継承元から継承先にメソッドを引き継ぐ場合、明示的に継承元のメソッドを呼び出したほうがよい。
理由は主に二つある。

①例えば、__init__を継承先のクラスで新しく定義してしまうと、継承元の__init__はオーバーライドされてしまうため
②継承元のメソッドや属性に変更が合った場合に、継承先へ反映させるのが容易なため

以下のようにすると、継承元のメソッドを崩さずしてメソッドを引き継ぐことができる。

class Anime():
    def __init__(self, airtime):
        self.airtime = airtime

    def introduce(self):
        print("放送時間: {}分".format(self.airtime))

class Nitijo(Anime):
    def __init__(self, airtime, honobonodo):
        super().__init__(airtime)
        self.honobonodo = honobonodo
    def introduce(self):
        print("ジャンル: 日常\n放送時間: {}分".format(self.airtime))

    def honobono(self):
        print("ほのぼの系の日常アニメ\nほのぼの度: {}".format(self.honobonodo))

class Battle(Anime):
    def __init__(self, airtime, gurodo):
        super().__init__(airtime)
        self.gurodo = gurodo
    def introduce(self):
        print("ジャンル: バトル\n放送時間: {}分".format(self.airtime))

    def guro(self):
        print("グロ系のバトルアニメ\nグロ度: {}".format(self.gurodo))

nitijo = Nitijo(30, 5)
nitijo.introduce()
nitijo.honobono()

battle = Battle(15, 10)
battle.introduce()
battle.guro()
ジャンル: 日常
放送時間: 30分
ほのぼの系の日常アニメ
ほのぼの度: 5

ジャンル: バトル
放送時間: 15分
グロ系のバトルアニメ
グロ度: 10

継承元の__init__に属性が追加されても以下のように変更すれば、反映されたことが分かりやすくなる。

class Anime():
    def __init__(self, airtime, company):
        self.airtime = airtime
        self.company = company

    def introduce(self):
        print("制作会社: {}\n放送時間: {}分".format(self.company, self.airtime))

class Nitijo(Anime):
    def __init__(self, airtime, company, honobonodo):
        super().__init__(airtime, company)
        self.honobonodo = honobonodo
    def introduce(self):
        print("制作会社: {}\nジャンル: 日常\n放送時間: {}分".format(self.company, self.airtime))

    def honobono(self):
        print("ほのぼの系の日常アニメ\nほのぼの度: {}".format(self.honobonodo))

class Battle(Anime):
    def __init__(self, airtime, company, gurodo):
        super().__init__(airtime, company)
        self.gurodo = gurodo
    def introduce(self):
        print("制作会社: {}\nジャンル: バトル\n放送時間: {}分".format(self.company, self.airtime))

    def guro(self):
        print("グロ系のバトルアニメ\nグロ度: {}".format(self.gurodo))

nitijo = Nitijo(30, "京都アニメーション", 5)
nitijo.introduce()
nitijo.honobono()

battle = Battle(15,"BONES", 10)
battle.introduce()
battle.guro()
制作会社: 京都アニメーション
ジャンル: 日常
放送時間: 30分
ほのぼの系の日常アニメ
ほのぼの度: 5

制作会社: BONES
ジャンル: バトル
放送時間: 15分
グロ系のバトルアニメ
グロ度: 10


普段使ってないから、どういう使い方をしたら良いのかわからないな・・・。
汎用的なクラスを継承して、用途に応じて具体的な処理を付け足していったりする感じ・・・?

うーん。難しい。


以上です。