Python初心者でも__hoge__使いたい！〜特殊属性，特殊メソッドの使い方〜

## 1.はじめに
Pythonでよくオブジェクト定義に用いられたり，いろんなオブジェクトに元からくっついてる`__`で囲まれた`__hoge__`や`__hoge__()`をそれぞれ特殊属性（特殊アトリビュート），特殊メソッドと言います．
これを使いこなしている人を見るとPython中級者以上感がするので僕も使いこなせるようになろうというメモです．

この特殊属性や特殊メソッドはオブジェクト指向の書き方です．Pythonのオブジェクト指向プログラミング（Object Oriented Programming）をOOPyと勝手に呼んでいるので是非使ってください．読み方は各自に任せます．

特殊属性や特殊メソッドは割といっぱいあるのでこの記事に順次追加していく予定です．

## 2.環境
- Python 3.6.0

## 3.特殊属性
### \_\_dict\_\_
そのオブジェクトのアトリビュート（変数とか配列とかメソッドではないもの）を辞書にして返す．

```python
class DictTest(object):
    def __init__(self):
        self.a = 1
        self.b = [1,2]      

    def c(self):
        pass

dicttest = DictTest()
print(dicttest.__dict__)
# {'a': 1, 'b': [1, 2]}
```
上のようにaとbのアトリビュートだけ格納されてます．cのメソッドについては格納されていません．

ちなみに[pythonチュートリアル](https://docs.python.jp/3/tutorial/classes.html#id2)によると，これを使うのは検死型のデバッガなどに限るべきだそうです．
これは，例えば`self.a`にアクセスするときは何か処理をしてから返すというようになっていた場合も，それを全部無視してアクセスできてしまうためだと思われます．

### \_\_doc\_\_
`def`定義や`class`定義宣言の直下に複数行コメントがあるとそれを読み込んで，ここに格納する．
`help()`によってこの情報を表示してくれる．
ちなみにサブクラスには継承されない．

```python
def doc_test_func1():
    """This function is ...
        hogehoge
    """
    pass

def doc_test_func2():
    pass


print(doc_test_func1.__doc__)
# This function is ...
#        hogehoge

help(doc_test_func1)

print(doc_test_func2.__doc__)
# None
# これにも__doc__アトリビュートはついてるが中身がNoneになっている．

help(doc_test_func2)
```

### \_\_annotations\_\_
関数注釈をすると，この`__annotations__`に情報が保存される．

ちなみに関数注釈とは，引数や返り値がどんなデータ型か人間用に見やすく表記する書き方である．
あくまでも人間用で，その注釈と違ったことをしてもエラーが出たりするわけではない．
詳細は[Pythonではじまる、型のある世界](https://qiita.com/icoxfog417/items/c17eb042f4735b7924a3)などを参照．

```python
# 関数注釈
def ann_test_func(param1: str, param2: int=1) -> str:
    output = param1 + str(param2)
    print(output)
    return output

print(ann_test_func.__annotations__)
# {'param1': <class 'str'>, 'param2': <class 'int'>, 'return': <class 'str'>}
# このように各引数や，返り値がどんなデータ型か辞書で保存されている．

ann_test_func("test", 1)
# test1

ann_test_func("test", "a")
# testa
# intの場所にstrを入れても怒られない．
```


### \_\_module\_\_
関数が定義されているモジュールの名前を返してくれます．

```python
class ModuleTest(object):
    pass

modeletest = ModuleTest()
ModuleTest.__module__
# __main__
```
pythonでは，対話型環境もひとつのモジュールで，その名前は`__main__`と名付けられているためこのように表示されます．

## 4.特殊メソッド
### \_\_init\_\_
~~オブジェクト指向で言われるところのコンストラクタ．~~
（下記コメントにあるようにイニシャライザと呼んだほうがいいようだ．Pythonには正確にこれがコンストラクタと呼べるものはないらしい．[__new__と__init__とメタクラスと](https://qiita.com/FGtatsuro/items/49f907a809e53b874b18)などを参照．）
インスタンス化するときに呼ばれる．


```python
class InitTest(object):
    def __init__(self):
      print("URYYYYYYYYYY")

inittest = InitTest() # ここで呼ばれる
# URYYYYYYYYYY
```

### \_\_iter\_\_, _\_next\_\_

`__iter__`は，[pythonドキュメント](https://docs.python.org/3.6/library/stdtypes.html#iterator-types)によるとイテレーターオブジェクトを返すものとある．つまり，元々イテレーターでないものを変換するといった処理を書くメソッドである．

```python
class IterTest(object):
    def __init__(self, *nums):
        self.nums = nums
        
    def __iter__(self):
        return iter(self.nums)

itertest = IterTest(1,2,3)
for i in itertest:
    print(i)
# 1
# 2
# 3
```

[`__next__`](https://docs.python.org/3.6/library/stdtypes.html#iterator.__next__)は，次の値を渡す部分を書き，もう渡すものがなくなったらStopIteration例外を出すように実装する．

詳細は[Pythonのイテレータとジェネレータ](https://qiita.com/tomotaka_ito/items/35f3eb108f587022fa09)を参照．この記事のサンプルコードを引っ張ってくると以下のような感じ．

```python
class MyIterator(object):
    def __init__(self, *numbers):
        self._numbers = numbers
        self._i = 0
    def __iter__(self):
        return self
    def __next__(self):
        # なぜか元の記事ではメソッド名がnextだが，__next__にすると動いた．
        if self._i == len(self._numbers):
            raise StopIteration()
        value = self._numbers[self._i]
        self._i += 1
        return value
```

### \_\_del\_\_
このメソッドはデストラクタとも呼ばれる．インスタンスが消滅させられるときに呼ばれる．

```python
class DelTest(object):
    def __del__(self):
        print("俺はまだ死にたくない！！")

deltest = DelTest()
del deltest
# 俺はまだ死にたくない！！
```

### \_\_call\_\_
オブジェクト自体をメソッドのように書いたとき，この`__call__`を実行する．

```python
class CallTest(object):
    def __call__(self):
        print("呼んだか？")

calltest = CallTest()
calltest()
# 呼んだか？
```

### \_\_setattr\_\_，\_\_getattr\_\_, \_\_delattr\_\_
`__setattr__`はアトリビュートに値を代入するときに呼ばれる．
`__getattribute__`はアトリビュートがあろうがなかろうが呼ばれる．親クラスの`__getattribute__`を使うとかしないとすぐに再帰的エラーになる．（`__getattribute__`の中で`__getattribute__`呼んで...が繰り返される．）
`__getattr__` はアトリビュートにアクセスするときに，そのアトリビュートがなかったときに呼ばれる．

```python
class SetGetDelattrTest(object):
    def __setattr__(self, name, value): 
        self.__dict__[name] = value
        print(f"{name} : {value} has been set!")

    def __getattribute__(self, name):
        print("URYYYYYY")
        return super().__getattribute__(name)

    def __getattr__(self, name):
        print(f"try to return value of {name}")
        raise AttributeError("nothing...")
        
    def __delattr__(self, name):
        print("not work!")

sgdattr = SetGetDelattrTest()
sgdattr.a = 1 # __setattr__
sgdattr.a # __getattribute__
sgdattr.b # __getattr__

del sgdattr.a # __delattr__
# not work!

sgdattr.a
# URYYYYYY
# 1
# __delattr__に消すコードを書いていないので生きてる．

```
`__setattr__`とかの中の`self.`でも呼ばれているらしくURYYYYYYURYYYYYYめっちゃうるさい．

これはアトリビュートへのアクセスの仕方全てに関する特殊メソッドだが，ぶっちゃけこの辺はあまり使わないと思われる．
実用上はあるアトリビュートに対して個別にsetとgetをいじりたい場合が多い．そんなときは次の`@property`デコレータを使うと便利です．

### @property
デコレータは，ある関数に対して，この関数はこういうものだという追加の設定ができるようなものです．
デコレータについては[Pythonのデコレータについて](https://qiita.com/mtb_beta/items/d257519b018b8cd0cc2e)あたり．
特に，`@property`に関しては[Python @property](https://www.programiz.com/python-programming/property)が良い感じです．

まず`@property`を使って，アトリビュートと同じ名前のメソッドを定義します．これがgetterになります．
次に同じ名前で`@x.setter`,`@x.deleter`デコレータを使って，値代入時に呼ばれるsetterや削除時に呼ばれるdeleterを定義していきます．（なくても良い）

注意点としては，オブジェクト内ではプライベート変数として`_x`を定義しておいて，対人間用としてアトリビュートxでsetしたりgetするようにすることです．
そうしないと，getterのところで，`object.x`でxの値を取りにいったときに，中の`return self.x`でまたgetterを呼び出して...と延々とループします．

```python
class PropertyTest(object):
    def __init__(self, x):
        self._x = x
        self.y = 1

    @property
    def x(self):
        print("getting x")
        return self._x

    @x.setter
    def x(self, x):
        if not isinstance(x, float):
            raise ValueError("hoge")

        print("setting x")
        self._x = x

    @x.deleter
    def x(self):
        print("頼む！殺さないでくれ！")
        del self._x

proptest = PropertyTest(x=10.)

proptest.x = 20.
# setting x

print(proptest.x)
# getting x
# 20.0

del proptest.x
# 頼む！殺さないでくれ！

print(proptest.y)
# 1
# アトリビュートyについては特に何も変更されていない．
```

アトリビュートyのgetterには特に何の変更もされておらず，xについてだけ修正されていることがわかります．

### \_\_dir\_\_
インスタンスに対して`dir()`をすると動くメソッド．
デフォルトから変更すると嬉しい理由が特に思いつかない．

```python
class DirTest(object):
    def __dir__(self):
        print("dirdirdir")
        return [1,2,3]

dirtest = DirTest()
dir(dirtest)
# dirdirdir
# [1, 2, 3]
```

## 5.reference
- https://docs.python.jp/3.5/reference/datamodel.html
- https://stackoverflow.com/questions/3278077/difference-between-getattr-vs-getattribute

## 6.おわりに
もっとOOPy触って育てたい．