Python Classをマスター

## はじめに
完全に備忘録!!
手元の環境が吹っ飛んでも良いように・・・
Pythonのclassはわかりやすいですね。rubyやjsのthisのように暗示的じゃないので、初めての言語にはもってこいだと思います!!

---
## class
selfはインスタンス生成時にインスタンス自身が自動で入る
下記はインスタンス自身のdateやuser_nameに引数を代入
constructor = インスタンス化時に自動で実行される
```python
# selfはインスタンス生成時にインスタンスが入る
class Person: # 2系は(object):が付く
  # 初期化メソッド(constructor)
  def __init__(self, name, age):
  # アトリビュート(プロパティ)
    self.name = name
    self.age = age
    
  # メソッド(第1引数は絶対にself)
  def message(self):
    return f"私の名前は{self.name}です。{self.age}歳です。"
  
  # 最後に呼ばれる(destructor)
  def __del__(self):
    print('Good Bye')
    
    
# インスタンス生成
baru = Person("baru", 20)

print(baru.message())

del baru # 明示的にdestructorを呼んでいる
```

## 継承
```python
class Car:
  def run(self):
    print('run')

class Matuda(Car): # Carを継承
  pass # passは何もしない時に指定する

matuda = Matuda()
matuda.run() # 継承先のメソッドが使える
```

## super
```python
# 親メソッドを呼び出し nameとageを用意
# 続けてJapanese特有の変数を用意
class Person():
  def __init__(self, name, age):
    self.name = name
    self.age = age
    

class Japanese(Person):
  def __init__(self, name, age, country):
    # 親メソッドを呼び出し
    super().__init__(name, age)
    # 独自の変数を定義
    self.country = country

baru = Japanese('けん', 18, '日本')
```

## 変数を非公開にする
`_1つの場合`参照はできるが、class内のみで使うことを明示する
直接`__name = '変更したい名前'`とした場合値を変更したのではなく、再定義している
バグに繋がるので良くない
```python
class Person():
  def __init__(self, name):
    self.__name = name # _を2つ
  
baru = Person('ばる')
print(baru.__name) # 参照できない
```

## getter と setter
直接ではなくgetter/setterを通してプロパティを参照・変更する
```python
class User():
  def __init__(self, name):
    self.__name = name
    
  # getter
  @property
  def name(self):
    return self.__name
  
  # setter
  @name.setter
  def name(self, value):
    self.__name = value
  
tee = User('tee')
# getter/setterは()が不要
tee.mame = 'cha' # setterで変更可能
print(tee.name) # getterで参照可能
```

## 抽象クラスを作成
`abcライブラリ`を用いて、継承先でのメソッド定義忘れを防止
非推奨のコードスタイル (推奨はダックタイピング)
```python
import abc # import abc

# abcを引数に指定して抽象クラスに
class Person(metaclass=abc.ABCMeta):
  def __init__(self, name):
    self.name = name

  # 下記記述で継承先のクラスはsayの定義が必須に
  @abc.abstractclassmethod
  def say(self):
    pass

class Japanese(Person):
  def __init__(self, name):
    super().__init__(name)

# sayメソッドの定義忘れによりエラーが発生する
tee = Japanese('tee')
```

## 多重継承
継承順序に気をつける
```python
class Person():
  def run(self):
    print('person: run')

class Car():
  def run(self):
    print('car: run')
    
  # 継承するものを,区切りで指定
  # 同じメソッドがある場合左側が優先される
class PersonCarRobot(Person, Car):
  def fly(self):
    print('fly')

robot = PersonCarRobot()
robot.run() # personのrunメソッドが走る
```

## クラス変数
```python
class Person():
  kind = 'human'
  
  def __init__(self, name):
    self.name = name
  
  # クラス内からはselfでもPersonでも可
  def who(self):
    print(self.name, self.kind)

p = Person('tee')
print(Person.kind) # クラス変数を参照
```

## classmethodとstaticmethod
```python
class Person():
  kind = 'human'
  
  # classメソッド
  # 自分のプロパティにアクセスする場合
  @classmethod
  def my_kind(cls):
    return cls.kind
  
  # staticメソッド
  # 自身のプロパティを参照しない場合
  @staticmethod
  def about():
    print('about human')

print(Person.my_kind()) # classmethod
Person.about() # staticmethod
```

## 特異メソッド
```python
# _がつくメソッド

class Word():

# インスタンスが文字列として使われた時に走る
# こんな感じのがいくつかある
  def __str__(self):
    return 'word...'
w = Word()
print(w)
```

## 終わりに
Railsが学習しやすそうだったんで、RailsでPF作ったことがあるのですが、やっぱり好きな言語。興味のある言語を学習するのが
最高ですね!!

Pythonしか勝たん!!
あ、Reactちゃんも好き!!