[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を使った際に呼び出されるのは後ろから