[python] super()とか継承とか__init__とか

# はじめに
これは単なる動作確認をメモしたものである。
[こちらを参考にしました](https://amzn.to/2xbp2Xv)

# 環境
python 3.6.9

# 複数のクラスで考える
- Birdクラスにはfly変数
- Fishクラスにはswim変数
- PenguinクラスはBirdクラスとFishクラスをインヘリタンスしている

## 失敗例①　クラス変数が継承されていない


```python
class Bird:
    def __init__(self):
        self.fly = 'i can flying'
        print(self.__class__.__name__ + 'クラスを作成')
        
class Fish:
    def __init__(self):
        self.swim = 'i can swimming'
        print(self.__class__.__name__ + 'クラスを作成')
        
class Penguin(Class1, Class2):
    def __init__(self):
        print(self.__class__.__name__ + 'クラスを作成')       
        
        
penguin = Penguin()
penguin.fly


# 実行結果
AttributeError: 'Penguin' object has no attribute 'fly'
```



## 失敗例②　継承失敗

Fishクラスのクラス変数はBirdクラスの`__init__`関数に上書きされてしまう

```python

class Bird():
    def __init__(self):
        self.fly = 'i can flying'
        print(self.__class__.__name__)
        
class Fish():
    def __init__(self):
        self.swim = 'i can swimming'
        print(self.__class__.__name__)
        
class Penguin(Bird, Fish):
    def __init__(self):
        super().__init__()
        print(self.__class__.__name__)
        
        
penguin = Penguin()
penguin.fly
penguin.swim


# 実行結果
AttributeError: 'Penguin' object has no attribute 'swim'
```

# 成功例

各々のクラスの`__init__`関数内でsuper()関数で`__init__'関数を明示的に継承することで上書きされることなく継承できる

```python
class Bird(object):
    def __init__(self):
        super(Bird, self).__init__()
        self.fly = 'i can flying'
        print('Birdクラスの中')
        
class Fish(object):
    def __init__(self):
        super(Fish, self).__init__()
        self.swim = 'i can swimming'
        print('Fishクラスの中')
        
class Penguin(Bird, Fish):
    def __init__(self):
        super(Penguin,self).__init__()
        print('Fishクラスの中')
        
        
penguin = Penguin()
print(penguin.fly)
print(penguin.swim)
```


# Pokemonで考える

## 基本構成
- Pokemonクラスはlifeとpowerのクラス変数をもっている
- PichuクラスはPokemonクラスをインヘリタンスしている
- PikachuクラスはPichuクラスをインヘリタンスしている
- RichuクラスはPikachuクラスをインヘリタンスしている


## デフォルト引数を使って初期化する
- Pichu,Pikachu,Raichuの初期値を設定した

```python
class Pokemon():
    def __init__(self, life=0, power=0):
        self.life = life 
        self.power = power 
        print('Pokemonクラス内')
        print(self.__class__.__name__ + 'クラス')
        print('life: {} power: {}'.format( self.life, self.power))
        print('\n↓\n')
        
class Pichu(Pokemon):
    def __init__(self, life=50, power=100):
        super().__init__(life, power)
        print('Pichuクラス内')
        print(self.__class__.__name__ + 'クラス')
        print('life: {} power: {}'.format( self.life, self.power))
        print('\n↓\n')
    def kamituku(self):
        print('かみつく')
        
class Pikachu(Pichu):
    def __init__(self, life=150, power=200):
        super().__init__(life, power)
        print('Pikachuクラス内')
        print(self.__class__.__name__ + 'クラス')
        print('life: {} power: {}'.format( self.life, self.power))
        print('\n↓\n')
    def denkishokku(self):
        print('電気ショック')
        
class Raichu(Pikachu):
    def __init__(self, life=200, power=250):
        super().__init__(life, power)
        print('Raichuクラス内')
        print(self.__class__.__name__ + 'クラス')
        print('life: {} power: {}'.format( self.life, self.power))
        print('\n')
    def kaminari(self):
        print('雷')
    def set(self, life, power):
        self.life = life
        self.power = power
        
print('---------------------------')
print('◯ pokemonインスタンス ◯')
print('---------------------------')
pokemon = Pokemon()

print('---------------------------')
print('◯ pichuインスタンス ◯')
print('---------------------------')
pichu = Pichu()

print('---------------------------')
print('◯ pikachuインスタンス ◯')
print('---------------------------')
pikachu = Pikachu()

print('---------------------------')
print('◯ raichuインスタンス ◯')
print('---------------------------')
raichu = Raichu()
raichu.kamituku()
raichu.denkishokku()
raichu.kaminari()
```

```:実行結果
---------------------------
◯ pokemonインスタンス ◯
---------------------------
Pokemonクラス内
Pokemonクラス
life: 0 power: 0

↓

---------------------------
◯ pichuインスタンス ◯
---------------------------
Pokemonクラス内
Pichuクラス
life: 50 power: 100

↓

Pichuクラス内
Pichuクラス
life: 50 power: 100

↓

---------------------------
◯ pikachuインスタンス ◯
---------------------------
Pokemonクラス内
Pikachuクラス
life: 150 power: 200

↓

Pichuクラス内
Pikachuクラス
life: 150 power: 200

↓

Pikachuクラス内
Pikachuクラス
life: 150 power: 200

↓

---------------------------
◯ raichuインスタンス ◯
---------------------------
Pokemonクラス内
Raichuクラス
life: 200 power: 250

↓

Pichuクラス内
Raichuクラス
life: 200 power: 250

↓

Pikachuクラス内
Raichuクラス
life: 200 power: 250

↓

Raichuクラス内
Raichuクラス
life: 200 power: 250


かみつく
電気ショック
雷
```



# 人間で考える

## 基本構成
- Humanはyarukiのメンバ変数をもっている
- TarouはHumanをインヘリタンスしている
- Tarouのyarukiの初期値は100
- Tarouのyarukiを50にセットする


## その①
- Humanは初期化変数をもっている
- Tarouは初期化変数をインヘリタンスする


```python
class Human:
    def __init__(self, yaruki):
         self.yaruki = yaruki
            
class Tarou(Human):
    def __init__(self,yaruki):
        super().__init__(yaruki)
    def set(self, yaruki):
        self.yaruki = yaruki
        
tarou = Tarou(100)
tarou.set(50) 
print(tarou.yaruki)

# 実行結果
50
```


## その②

- Human, Tarouともに初期化変数をもっていない
- Tarouはyarukiの初期値は100

```python
class Human:
    def __init__(self):
         self.yaruki
            
class Tarou(Human):
    def __init__(self):
        self.yaruki = 100
    def set(self, yaruki):
        self.yaruki = yaruki
        
        
tarou = Tarou()
tarou.set(50) 
tarou.yaruki

# 実行結果
50
```