お勉強中

はまった。キモい慣れない。まずは言語仕様みろって話ですね、そうですね

インスタンスからクラス変数に代入してみる

きもいことすんなっていわれる

>>> class Test(object):
...     classField = 'hogehoge'
... 
>>> test = Test()
>>> test.classField
'hogehoge'
>>> test.__dict__
{}
>>> test.classField = 'mogemoge'
>>> test.classField
'mogemoge'
>>> test.__dict__
{'classField': 'mogemoge'}
>>> test.tyaugana = 'tyaimaxngana'
>>> test.tyaugana
'tyaimaxngana'
>>> test.__dict__
{'tyaugana': 'tyaimaxngana', 'classField': 'mogemoge'}

インスタンスでクラス変数に代入すると、同名のクラス変数があろうが新しくインスタンス変数が生成される。この挙動は、あるスコープの内部のスコープで、外側のスコープの変数に代入した時と同じように思える

>>> def outer():
...     hoge = 'hoge'
...     def inner():
...             print hoge
...             hoge = 'fuga'
...     inner()
... 
>>> outer()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in outer
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'hoge' referenced before assignment

なんでやねん!!!って静的な誰もがおもうだろうけど、この挙動は正しい

スコープは静的に決定されますが、動的に使用されます。

Python 特有の癖として、代入を行うと名前がいつも最も内側のスコープに入るというものがあります。

http://www.python.jp/doc/2.4/tut/node11.html#SECTION0011200000000000000000

上の例だと、inner()内でhogeに代入が行われているから、hogeのスコープはinner()内部になる。だからその直前のprint文で参照してるhogeは未定義ということになって怒られるわけ

クラス変数とインスタンス変数の定義、参照、変更

  • クラス変数
>>> class Test(object):
...     classField = 'hoge' #クラス変数の定義はclassブロック直下で行う
...     def hoge(self):
...             print Test.classField #参照はクラス名か
...             print self.classField #selfで。でも最初の例もあるし、クラス名のほうがいい?
... 
>>> Test.classField
'hoge'
>>> Test.classField = 'fuga' #変更はクラス名から
>>> Test.classField
'fuga'
>>> test = Test()
>>> test.hoge()
fuga
fuga
>>> Test.mogemoge = 'moge' #クラスの外側から新しく
>>> test.mogemoge
'moge'
>>> class Test(object):
...     def __init__(self):
...             self.instanceField = 'fuga' # 定義は__init__()内で行う
...     def fuga(self):
...             print self.instanceField # クラス宣言内での参照はself
... 
>>> test = Test()
>>> test.instanceField
'fuga'
>>> test.fuga()
fuga
>>> test.instanceField = 'moge' # インスタンスから変更
>>> test.fuga()
moge
>>> test.mogerattyo = 'mogerattyo' #やっぱり定義できる
>>> test.mogerattyo
'mogerattyo'

感想

宣言ほしい