Python の特殊メソッド(ダンダーメソッド)紹介。　オブジェクト同士の加算や、オブジェクトの表示をカスタマイズ

## はじめに
Pythonにはたくさんの特殊メソッド(ダンダーメソッド)がありますが、今回は自作クラスに使えるものを紹介します。

## 本文
### 今回の前提
説明するのに使う体重classです。
このクラスには、体重だけでなく、測定した日付も格納されています。
それぞれ、A君、B君のインスタンスを生成しています。
```python
class Body_weight:
    def __init__(self,weight,recorded_date) -> None:
        # 体重
        self.weight = weight
        # 体重の測定した日付
        self.recorded_date = recorded_date

A_weight = Body_weight(75,"2024-1-20")
B_weight = Body_weight(46,"2023-11-21")
```
<br>

### 紹介するメソッドの一覧
| メソッド名 | 呼び出せれるタイミング |
|:-:|:-:|
| \_\_str__ | print(obj) |
| \_\_int__ | int(obj) |
| \_\_add__ | obj + hoge |

### \_\_str__ の説明
printされた時に呼び出されます。
これを定義しないと通常では下記のようになります。
```python
A_weight = Body_weight(75,"2024-1-20")
print(A_weight)

""" 出力 """
# <__main__.Body_weight object at 0x0000025F70832310>
```

ですが、下記のように定義すると...
```python
class Body_weight:
    def __init__(self,weight,recorded_date) -> None:
        # 体重
        self.weight = weight
        # 体重の測定し日付
        self.recorded_date = recorded_date
        
    def __str__(self):
        return f"測定日:{self.recorded_date}  体重:{str(self.weight)}"
        
A_weight = Body_weight(75,"2024-1-20")
print(A_weight)

"""出力"""
# 測定日:2024-1-20  体重:75
```
このように表示してくれるようになります。
<br>

### \_\_int__ の説明
intへキャストする時に呼び出されます。
これを定義しないと通常では下記のようになります。
```python
A_weight = Body_weight(75,"2024-1-20")
print(int(A_weight))

"""出力"""
# TypeError: int() argument must be a string, a bytes-like object or a real number, not 'Body_weight'
```
Errorになっちゃいますね。
ですが、下記のように定義すると...
```python
class Body_weight:
    def __init__(self,weight,recorded_date) -> None:
        # 体重
        self.weight = weight
        # 体重の測定し日付
        self.recorded_date = recorded_date
        
    def __int__(self):
        return self.weight

A_weight = Body_weight(75,"2024-1-20")
print(int(A_weight))

"""出力"""
# 75
```
しっかりとキャストしくれるようになります。
<br>

### \_\_add__ の説明
加算の処理の時に呼び出されるものです。
これを定義しないと通常では下記のようになります。
```python
A_weight = Body_weight(75,"2024-1-20")
print(A_weight + 100)

"""出力"""
# TypeError: unsupported operand type(s) for +: 'Body_weight' and 'int'
```
Errorになっちゃいますね。
ですが、下記のように定義すると...
```python
class Body_weight:
    def __init__(self,weight,recorded_date) -> None:
        # 体重
        self.weight = weight
        # 体重の測定し日付
        self.recorded_date = recorded_date
    
    def __add__(self, other):
        return self.weight  + other

A_weight = Body_weight(75,"2024-1-20")
print(A_weight + 100)

"""出力"""
# 175
```
しっかし加算してくれましたが、まだ、下記の場合に対応できていません！
```python
A_weight = Body_weight(75,"2024-1-20")
B_weight = Body_weight(46,"2023-11-21")

print(A_weight + B_weight)

"""出力"""
# unsupported operand type(s) for +: 'int' and 'Body_weight'
```
このエラーがでる原因は、\_\_add__の引数のotherがintでないからですね...
先ほど紹介した\_\_int__を組み合わせると解決します！
```python
class Body_weight:
    def __init__(self,weight,recorded_date) -> None:
        # 体重
        self.weight = weight
        # 体重の測定し日付
        self.recorded_date = recorded_date

    def __int__(self):
        return self.weight
    
    def __add__(self, other):
        return self.weight  + int(other)

A_weight = Body_weight(75,"2024-1-20")
B_weight = Body_weight(45,"2023-11-21")

print(A_weight + B_weight)

"""出力"""
# 120
```
これで、加算対象がint型でも同じBody_weightでも動くようになりました！
<br>

#### その他の演算
加算以外にも、以下のような演算をオーバーライド可能です。
| メソッド名 | 呼び出せれるタイミング |
|:-:|:-:|
| \_\_mul__ |  obj * 2 |
| \_\_truediv__ | obj / 2 |
| \_\_mod__ | obj % 2 |

## 最後に
覚えておくといつか使えそうですよね。
調べてみてとても楽しかった。