209
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

[Python]クラス継承(super)

クラス継承

名前の通り,基底クラスの機能を持った派生クラスを作ります.
*途中で力尽きたので多分加筆します

一つのクラスの継承

ここは,単純に,Creatureクラスを元に,Warrior, Magicianクラスを作ってます.
初期levelに応じて,能力を上昇させています.

status(self)関数では,パラメータの列挙を行っています.(テスト用)
__init__ はインスタンス生成の際に実行されます.
Worrior, Magicianクラスでは,武器をもたせたり,職業名の変更を行っています.

clas_test1.py
class Creature(object):
    def __init__(self, level=1, weapon=None):
        self.level = level
        self.hp = 0
        self.mp = 0
        self.attack = 0
        self.defence = 0
        self.weapon = weapon
        self.job = "neet"

    def status(self):
        return "Job:{} | HP:{} | MP:{} | Atk:{} | Def:{} | Weapon:{}".format \
                (self.job, self.hp, self.mp, self.attack, self.defence, self.weapon)


class Warrior(Creature):
    def __init__(self, level):
        super().__init__(level)
        self.attack += 3 * level
        if self.weapon is None:
            self.weapon = "sword"
        if self.job == "neet":
            self.job = "Warrior"
        else: self.job += "Warrior"


class Magician(Creature):
    def __init__(self, level):
        super().__init__(level)
        self.mp += 4 * level
        if self.weapon is None:
            self.weapon = "rod"
        if self.job == "neet":
            self.job = "Magic"
        else: self.job += "Magic"

下のようにlevelに応じて能力の上昇,基底クラスのstatus関数が使えています.

test1.py
>>> print(Warrior(5).status())
Job:Warrior | HP:0 | MP:0 | Atk:15 | Def:0 | Weapon:sword
>>> print(Magician(5).status())
Job:Magic | HP:0 | MP:20 | Atk:0 | Def:0 | Weapon:rod

複数クラス継承

複数クラスの場合も先ほどとやることはほとんど同じです.

class_test2.py
class MagicWarrior(Warrior, Magician):
    def __init__(self, level):
        super().__init__(level)


class WarriorMagic(Magician, Warrior):
    def __init__(self, level):
        super().__init__(level)

ここで,注意する点は,下の出力でわかるように,
super()を用いた時__init__が呼ばれる順番が後ろからになります.
この順番は,mro()で確認ができます.

test2.py
>>> print(MagicWarrior(5).status())
Job:MagicWarrior | HP:0 | MP:20 | Atk:15 | Def:0 | Weapon:rod
>>> print(WarriorMagic(5).status())
Job:WarriorMagic | HP:0 | MP:20 | Atk:15 | Def:0 | Weapon:sword
>>>
>>> WarriorMagic.mro()
[<class 'class_test.WarriorMagic'>, <class 'class_test.Magician'>, <class 'class_test.Warrior'>, <class 'class_test.Creature'>, <class 'object'>]

superを使わないとどうなるか,

例えば,

class_test3.py
class WarriorMagic(Magician, Warrior):
    def __init__(self, level):
        # super().__init__(level)
        Warrior.__init__(self, level)
        Magician.__init__(self, level)

一見,同じように見えるのですが,initの呼び出しの回数が違います.
この場合,Warrior > Creature, Magician > Warrior > Creature
といった感じで呼び出しています.

superを使った場合では,Magician > Warrior > Creature
と呼び出し回数が違います.

Job:WarriorMagic | HP:0 | MP:20 | Atk:15 | Def:0 | Weapon:sword

さらに,基底クラスのWarriorとMagicianクラスもsuperを使わずに定義すると

class_test4.py
class Warrior(Creature):
    def __init__(self, level):
        # super().__init__(level)
        Creature.__init__(self, level)
        self.attack += 3 * level
        if self.weapon is None:
            self.weapon = "sword"
        if self.job == "neet":
            self.job = "Warrior"
        else: self.job += "Warrior"


class Magician(Creature):
    def __init__(self, level):
        # super().__init__(level)
        Creature.__init__(self, level)
        self.mp += 4 * level
        if self.weapon is None:
            self.weapon = "rod"
        if self.job == "neet":
            self.job = "Magic"
        else: self.job += "Magic"
test4.py
Job:Magic | HP:0 | MP:20 | Atk:0 | Def:0 | Weapon:rod

こうすると,せっかく最初のWarriorで能力とかをつけたのに,
Magicianで2回目のinitを呼び出したせいで,パラメタが初期化され,ただのMagicianの能力しか割り振られていません.
その結果,下のようになってしまいます.

流れ的には,
Warrior > Creature, Magician > Creature
のような感じで呼び出されていて,見てわかる通りCreatureを2回呼び出されていて,先ほどとは違い,2回目にWarriorが呼び出されていないので,Worriorのinitが反映されない形になってしまってます.

まとめ

とりあえず,継承する際はsuperを基本的に使う
superを使った際に呼び出されるのは後ろから

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
209
Help us understand the problem. What are the problem?