Python classの使い方

```python
class Student:
    def __init__(
        self, name: str, japanese_point: int, arithmetic_point: int, english_point: int
    ) -> None:
        self.name: str = name
        self.japanese_point: int = japanese_point
        self.arithmetic_point: int = arithmetic_point
        self.english_point: int = english_point
        self.avg_point: float
    
    # 平均点計算
    def avg(self) -> None:
        total_point: int = (
            self.japanese_point + self.arithmetic_point + self.english_point
        )
        self.avg_point = round(total_point / 3, 1)  # 小数点第1位以下四捨五入

    # 平均点表示
    def show_avg(self) -> None:
        print(f"{self.name}さんの平均点は{self.avg_point}点です。")


def main():
    # 田中さんの処理
    tanaka_st = Student("田中", 65, 39, 87)
    tanaka_st.avg()
    tanaka_st.show_avg()

    # 佐藤さんの処理
    satou_st = Student(
        name="佐藤", japanese_point=92, arithmetic_point=55, english_point=36
    ) # この書き方の方がわかりやすい
    satou_st.avg()
    satou_st.show_avg()


if __name__ == "__main__":
    main()
```

田中さんと佐藤さんの平均点を表示するプログラムです。
class内で平均点を計算し、その平均点を表示するという処理です。

## コンストラクタ

`def __init__`は、**初期値を設定する場所**。
`Student("田中", 65, 39, 87)`で`name`、`japanese_point`、`arithmetic_point`、`english_point`の値をクラスの引数に渡します。
`def __init__`の中でそれぞれの値をセットしています。

## 引数selfをお忘れなく！

**pythonではclass内の関数の引数に必ず`self`を含めます**。
`def avg(self):`のように。
これは`__init__`で初期値を代入した`self.`の変数を継承しています。
何も引数で渡すものがなくても必ず`self`を渡します。
あるあるとして、`self`を渡すのを忘れていてエラーがでること。

## self.の値について

コンストラクタで設定した値(self.の値)がclass内の他の関数の中で値が変わった場合、そのまま継承されていきます。
今回だと`self.avg_point`はコンストラクタ`def __init__`の中では、定義だけで値は何も代入されていません。
`avg関数`の中で`self.avg_point`に平均点が代入されました。
`show_avg関数`で`self.avg_point`を表示していますが、`avg関数`で代入した数値がそのまま表示されています。
`self.`の変数はclass内に限り、関数をまたいで使い回しができます。

## もし関数だけで組んだら

↑のクラスをすべて関数だけでやった場合。

```python
def avg(
    name: str, japanese_point: int, arithmetic_point: int, english_point: int
) -> float:
    total_point: int = japanese_point + arithmetic_point + english_point
    avg_point: float = round(total_point / 3, 1)  # 小数点第1位以下四捨五入
    return avg_point


def show_avg(name: str, avg_point: float) -> None:
    print(f"{name}さんの平均点は{avg_point}点です。")


def main():
    # 田中さんの処理
    name: str = "田中"
    japanese_point: int = 65
    arithmetic_point: int = 39
    english_point: int = 87
    avg_point: float = avg(name, japanese_point, arithmetic_point, english_point)
    show_avg(name, avg_point)

    # 佐藤さんの処理
    name = "佐藤"
    japanese_point = 92
    arithmetic_point = 55
    english_point = 36
    avg_point = avg(name, japanese_point, arithmetic_point, english_point)
    show_avg(name, avg_point)


if __name__ == "__main__":
    main()
```

処理自体が少ないのでそんなに行数は変わりませんが、多くなってきた場合、関数だけで書くと膨大な行数になり同じことを連続して書かないといけなくなったりします。
あと、関数だけだと毎回引数で渡す必要が出てきます。
クラスの場合だと、コンストラクタで管理されているので、`self`だけ渡せばOKになります。

## アノテーションをつけよう！

classに限ったことではないのですが、アノテーションをつけた方が、みやすいしあとあとのメンテナンス性も上がります。
チーム開発のときでも他の人がみて一目でどんなデータが入っているのかがわかります。
基本的に変数定義と関数の引数、返り値につけます。

```python
# 変数定義
name: str = "田中"
point: int = 65
```

```python
# 関数の引数
def show_avg(name: str, avg_point: float):
# これだと引数の中に何が入っているのかわかりにくい。
def show_avg(name, avg_point):
```

`name`はなんとなく文字が入ってるんだろうなと想像できますが、`avg_point`の場合はpointなので数値なんだろうけどint型なのかfloat型なのかまた他の型なのかがパッと見わからない。
なのでアノテーションをつけることでわかりやすくなる。

```python
# 関数の返り値
def avg(引数) -> float:
```

関数内で`return`で何が返っているのか確認しなくても、float型が返っているのがわかる。