Pythonで存在しないインスタンス変数に参照・代入した時の挙動

[こちらの記事](https://qiita.com/gothedistance/items/8e0192bfa24cfa80b840)をみて手元で実験してみたメモです

#### プロパティの参照時

1. まずインスタンス変数をみにいく
2. みつからなければクラス変数をみにいく
3. みつからなければAttributeErrorを吐く

#### プロパティへ代入時

1. インスタンス変数が定義されていれば、インスタンス変数を上書きする。
2. インスタンス変数が存在しなければ、新しくインスタンス変数を作る。

>クラス変数は操作されないことに注意！

```python
In [1]: class Sample:
   ...:     name = 'name'
   ...:     

In [2]: s = Sample()

In [3]: s2 = Sample()

In [4]: vars(s)
Out[4]: {}

In [5]: vars(s2)
Out[5]: {}

In [6]: vars(Sample)
Out[6]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Sample' objects>,
              '__doc__': None,
              '__module__': '__main__',
              '__weakref__': <attribute '__weakref__' of 'Sample' objects>,
              'name': 'name'})

In [7]: s.name
Out[7]: 'name'

In [8]: s.hoge
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-57bae294f764> in <module>()
----> 1 s.hoge

AttributeError: 'Sample' object has no attribute 'hoge'

In [9]: s.name = 'spam'

In [10]: vars(s)
Out[10]: {'name': 'spam'}

In [11]: vars(s2)
Out[11]: {}

In [12]: vars(Sample)
Out[12]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Sample' objects>,
              '__doc__': None,
              '__module__': '__main__',
              '__weakref__': <attribute '__weakref__' of 'Sample' objects>,
              'name': 'name'})

In [13]: s.name
Out[13]: 'spam'

In [14]: s2.name
Out[14]: 'name'

In [15]: Sample.a_list = [1, 2, 3, 4]

In [16]: vars(Sample)
Out[16]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Sample' objects>,
              '__doc__': None,
              '__module__': '__main__',
              '__weakref__': <attribute '__weakref__' of 'Sample' objects>,
              'a_list': [1, 2, 3, 4],
              'name': 'name'})

In [17]: vars(s)
Out[17]: {'name': 'spam'}

In [18]: vars(s2)
Out[18]: {}

In [19]: s.a_list.append(5)

In [20]: vars(s)
Out[20]: {'name': 'spam'}

In [21]: vars(s2)
Out[21]: {}

In [22]: vars(Sample)
Out[22]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Sample' objects>,
              '__doc__': None,
              '__module__': '__main__',
              '__weakref__': <attribute '__weakref__' of 'Sample' objects>,
              'a_list': [1, 2, 3, 4, 5],
              'name': 'name'})

In [23]: s.a_list
Out[23]: [1, 2, 3, 4, 5]

In [24]: s2.a_list
Out[24]: [1, 2, 3, 4, 5]

In [25]: s.b_list.append(6)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-25-1b7de7185c15> in <module>()
----> 1 s.b_list.append(6)

AttributeError: 'Sample' object has no attribute 'b_list'

In [26]: s.b_list = [10, 20, 30]

In [27]: vars(s)
Out[27]: {'b_list': [10, 20, 30], 'name': 'spam'}

In [28]: vars(s2)
Out[28]: {}

In [29]: vars(Sample)
Out[29]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Sample' objects>,
              '__doc__': None,
              '__module__': '__main__',
              '__weakref__': <attribute '__weakref__' of 'Sample' objects>,
              'a_list': [1, 2, 3, 4, 5],
              'name': 'name'})

In [30]: s.b_list
Out[30]: [10, 20, 30]

In [31]: s2.b_list
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-31-78dac7181190> in <module>()
----> 1 s2.b_list

AttributeError: 'Sample' object has no attribute 'b_list'
```