[Python] 特殊メソッドまとめ

# はじめに

個人的に特殊メソッドはわりと使うのですが、調べる度にいろんなサイトを参照している気がするので1つにまとめておきたいと思います。
特殊メソッドはそれぞれ実行される条件が違うのですが、大まかに分けると以下のようになるかと思います。


# 条件
- 初期化
- 組み込み関数
- 算術演算子
  - 代数演算子
  - 代入演算子
- 比較演算子
- コンテナ(リストや辞書)操作
- 属性操作
- withステートメント

# 初期化

インスタンス作成時に実行されるメソッドです。`__del__`は削除時。

```python
class Initialize:
    def __new__(cls):
        # インスタンス作成時
        print("New")
        return super().__new__(cls)

    def __init__(self):
        # インスタンス作成時
        print('Init')

    def __del__(self):
        # del オブジェクト のとき実行される
        del self
```

```python
initialize = Initialize()
del initialize
```
>New
Init

`__new__`と`__init__`の違いについては、[こちら](https://qiita.com/FGtatsuro/items/49f907a809e53b874b18)の記事をどうぞ。

# 組み込み関数

組み込みの関数によって実行されるメソッドです。

```python
class BuiltIn:
    def __init__(self):
        self.__number = 10
        self.__string = 'Hello'

    def __bool__(self):
        # bool(オブジェクト)のとき
        import random
        random_number = random.randint(10,11)
        return self.__number == random_number
    
    def __bytes__(self):
        # bytes(オブジェクト)のとき
        return bytes(self.__string, encoding='utf-8')
    
    def __complex__(self):
        # complex(オブジェクト)のとき
        return complex(self.__number)
    
    def __float__(self):
        # float(オブジェクト)のとき
        return float(self.__number)
    
    def __int__(self):
        # int(オブジェクト)のとき
        return int(self.__number)

    def __str__(self):
        # str(オブジェクト)のとき
        return self.__string
    
    def __len__(self):
        # len(オブジェクト)のとき
        return len(self.__string)

    def __repr__(self):
        # repr(オブジェクト)のとき
        return f'{self.__string} World'
    
    def __hash__(self):
        # hash(オブジェクト)のとき
        return hash(self.__number)

    def __abs__(self):
        # abs(オブジェクト)のとき
        return abs(self.__number)
    
    def __format__(self, form_spec):
        # '{}'.format(オブジェクト)のとき
        return self.__string
```

```python
builtin = BuiltIn()
print(bool(builtin))
print(bytes(builtin))
print(complex(builtin))
print(float(builtin))
print(int(builtin))
print(str(builtin))
print(len(builtin))
print(repr(builtin))
print(hash(builtin))
print('{} World'.format(builtin))
```

>True
b'Hello'
(10+0j)
10.0
10
Hello
5
Hello World
10
Hello World

# 算術演算子

算術演算によって実行されるメソッドです。

## 代数演算子

通常の +、- などのような演算子によって実行されるメソッドです。

```python
class Arithmetic:
    def __init__(self, x):
        self.x = x

    def __add__(self, other):
        # オブジェクト + オブジェクトのとき
        return self.x + other.x

    def __sub__(self, other):
        # オブジェクト - オブジェクトのとき
        return self.x - other.x

    def __mul__(self, other):
        # オブジェクト * オブジェクトのとき
        return self.x * other.x

    def __truediv__(self, other):
        # オブジェクト / オブジェクトのとき
        return self.x / other.x

    def __floordiv__(self, other):
        # オブジェクト // オブジェクトのとき
        return self.x // other.x

    def __mod__(self, other):
        # オブジェクト % オブジェクトのとき
        return self.x % other.x

    def __pow__(self, other):
        # オブジェクト ** オブジェクトのとき
        return self.x ** other.x

    def __and__(self, other):
        # オブジェクト & オブジェクトのとき
        return self.x & other.x

    def __xor__(self, other):
        # オブジェクト ^ オブジェクトのとき
        return self.x ^ other.x

    def __or__(self, other):
        # オブジェクト | オブジェクトのとき
        return self.x | other.x

    def __lshift__(self, other):
        # オブジェクト << オブジェクトのとき
        return self.x << other.x

    def __rshift__(self, other):
        # オブジェクト >> オブジェクトのとき
        return self.x >> other.x

    def __neg__(self):
        # +オブジェクトのとき
        return -self.x

    def __pos__(self):
        # -オブジェクトのとき
        return +self.x

```

```python
a = Arithmetic(1)
b = Arithmetic(2)

print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a // b)
print(a % b)
print(a ** b)
print(a & b)
print(a | b)
print(a << b)
print(a >> b)
print(a ^ b)
print(+a)
print(-a)
```

>3
-1
2
0.5
0
1
1
0
3
4
0
3
1
-1

## 代入演算子

+=、-= などのような演算子によって実行されるメソッドです。

```python
class Arithmetic:
    def __init__(self, x):
        self.x = x

    def __iadd__(self, other):
        # オブジェクト += オブジェクトのとき
        self.x += other.x
        return self

    def __isub__(self, other):
        # オブジェクト -= オブジェクトのとき
        self.x -= other.x
        return self

    def __imul__(self, other):
        # オブジェクト *= オブジェクトのとき
        self.x *= other.x
        return self

    def __itruediv__(self, other):
        # オブジェクト /= オブジェクトのとき
        self.x /= other.x
        return self

    def __ifloordiv__(self, other):
        # オブジェクト //= オブジェクトのとき
        self.x //= other.x
        return self

    def __imod__(self, other):
        # オブジェクト %= オブジェクトのとき
        self.x %= other.x
        return self

    def __ipow__(self, other):
        # オブジェクト **= オブジェクトのとき
        self.x **= other.x
        return self

    def __iand__(self, other):
        # オブジェクト &= オブジェクトのとき
        self.x &= other.x
        return self

    def __ixor__(self, other):
        # オブジェクト ^= オブジェクトのとき
        self.x ^= other.x
        return self

    def __ior__(self, other):
        # オブジェクト |= オブジェクトのとき
        self.x |= other.x
        return self

    def __ilshift__(self, other):
        # オブジェクト <<= オブジェクトのとき
        self.x <<= other.x
        return self

    def __irshift__(self, other):
        # オブジェクト >>= オブジェクトのとき
        self.x >>= other.x
        return self
```

```python
a = Arithmetic(1)
b = Arithmetic(2)

a += b
print(a.x)
a -= b
print(a.x)
a *= b
print(a.x)
a **= b
print(a.x)
a &= b
print(a.x)
a |= b
print(a.x)
a <<= b
print(a.x)
a >>= b
print(a.x)
a ^= b
print(a.x)
a /= b
print(a.x)
a //= b
print(a.x)
a %= b
print(a.x)
```

>3
1
2
4
0
2
8
2
0
0.0
0.0
0.0


# 比較演算子

比較演算によって実行されるメソッドです。

```python
class Comparison:
    def __init__(self, x):
        self.x = x

    def __eq__(self, other):
        # オブジェクト == オブジェクトのとき実行
        return self.x == other.x

    def __ne__(self, other):
        # オブジェクト != オブジェクトのとき実行
        return self.x != other.x

    def __lt__(self, other):
        # オブジェクト < オブジェクトのとき実行
        return self.x < other.x

    def __le__(self, other):
        # オブジェクト <= オブジェクトのとき実行
        return self.x <= other.x

    def __gt__(self, other):
        # オブジェクト > オブジェクトのとき実行
        return self.x > other.x

    def __ge__(self, other):
        # オブジェクト >= オブジェクトのとき実行
        return self.x >= other.x

```

```python
cp_1 = Comparison(10)
cp_2 = Comparison(11)

print(cp_1 == cp_2)
print(cp_1 != cp_2)
print(cp_1 < cp_2)
print(cp_1 <= cp_2)
print(cp_1 > cp_2)
print(cp_2 >= cp_2)
```

>False
True
True
True
False
True

# コンテナ（リストや辞書）操作

リストや辞書の値を設定したり、取得したりするときに実行されるメソッドです。

```python
class Container:
    def __init__(self, arr, dic=None):
        self.__arr = arr
        self.__dic = dic

    def __getitem__(self, key):
        # オブジェクト[key]のとき実行
        return self.__arr[key]	

    def __setitem__(self, key, value):
        # オブジェクト[key]=valueのとき実行
        self.__arr[key] = value
        return self

    def __delitem__(self, key):
        # del オブジェクト[key]のとき実行
        del self.__arr[key]
        return self

    def __iter__(self):
        # iter(オブジェクト)のとき実行
        return iter(self.__arr)

    def __contains__(self, item):
        # item in オブジェクト のとき実行
        return item in self.__dic

    def __reversed__(self):
        # reversed(オブジェクト)のとき実行
        return reversed(self.__arr)
```

```python
container = Container([1,2,3,5], dic={"name":"hiroshi", "age":"28"})

print(len(container))
print(container[1])
container[1] = 7
print(container[1])
del container[1]
print(container[1])
print(list(iter(container)))
print('address' in container)
print(list(reversed(container)))
```

>4
2
7
3
[1, 3, 5]
False
[5, 3, 1]


# 属性操作
オブジェクトの属性値を設定したり、取得したりするときに実行されるメソッドです。

```python
class Attribute:
    def __setattr__(self, name, value):
        # 属性を追加するとき
        self.__dict__[name] = value

    def __getattr__(self, name):
        # 属性を取得するとき
        raise AttributeError("nothing...")

    def __delattr__(self, name):
        # 属性を削除するとき
        del self.__dict__[name]
    
    def __getattribute__(self, name):
        # 上記のような属性にアクセスするときを
        print("Hello")
        return super().__getattribute__(name)

```

```python
attribute = Attribute()
attribute.x = 1
print(attribute.x)
del attribute.x
```
>Hello
Hello
1
Hello

詳しくは[こちら](https://qiita.com/virusyun/items/db64737d1c60cdcbd25e)をどうぞ。

# withステートメント
with文によって実行されるメソッドです。


```python
class With:
    def __init__(self, x):
        self.x = x

    def __enter__(self):
        # with オブジェクト as obj: のとき実行
        self.x += 1
        print('enter', self.x)
        return self

    def __exit__(self, ex_type, ex_value, trace):
        # withの終わりで実行
        self.x += 1
        print(ex_type)
        print(ex_value)
        print(trace)
        print('exit', self.x)
```

```python
with With(1) as w:
    print('hello')
```

>enter 2
hello
None
None
None
exit 3



# 参考
・[［Pythonチートシート］特殊メソッド編](https://atmarkit.itmedia.co.jp/ait/articles/2002/18/news007.html)
・[Pythonの特殊メソッド一覧を備忘録としてまとめてみた。](https://qiita.com/y518gaku/items/07961c61f5efef13cccc)
・[Python初心者でも__hoge__使いたい！〜特殊属性，特殊メソッドの使い方〜](https://qiita.com/kazetof/items/751be29f208836cf9bf4)

# まとめ
ここにあげたもの以外で便利なメソッドをご存じの方いましたらコメントいただけると嬉しいです。改めてまとめてみると勉強になった部分もあるので今後もこのようなまとめ記事を書いていけたらと思います。