Python は変数に値を格納せず、オブジェクトに名前を割り当てます。locals()関数は、現在の名前空間 (具体的には現在のスコープ) 内のすべての名前を返します。新しい通訳セッションを開始して、何locals()
が得られるか見てみましょう。
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
現在名前空間にある唯一の名前は、Python が起動時にそこに置く組み込みの名前です。ここでは、割り当てた名前のみを示す簡単なワンライナーを示します。
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{}
その方がいいです。ワンライナーがどのように機能するかについて心配する必要はありません。先に進んでクラスを作成しましょう。
>>> class C(object):
greeting = "I'm the first class"
クラスを定義すると、現在のスコープ内の場所に名前が表示されます。
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'C': <class '__main__.C'>}
この部分は、大きすぎて出力できないオブジェクトがあることを Python で表現したものですが、それは私たちが定義したクラス オブジェクトです。クラスオブジェクトが格納されているメモリアドレスを見てみましょう。id()関数を使用して調べることができます。
>>> id(C)
18968856
返される数値id()
は、引数のメモリ位置です。これらのコマンドを自分で実行すると、別の数値が表示されますが、1 回のセッションで数値が変わることはありません。
>>> id(C)
18968856
では、インスタンスを作成しましょう。
>>> c = C()
>>> c.greeting
"I'm the first class"
を見るとlocals()
、クラス オブジェクトとインスタンス オブジェクトの両方が見えます。
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'C': <class '__main__.C'>, 'c': <__main__.C object at 0x011BDED0>}
すべてのインスタンス オブジェクトには__class__
、インスタンスがインスタンスであるクラス オブジェクトへの参照である特別なメンバーがあります。
>>> c.__class__
<class '__main__.C'>
その変数を呼び出すと、定義したばかりid()
のクラスへの参照であることがわかります。C
>>> id(c.__class__)
18968856
>>> id(c.__class__) == id(C)
True
C
次に、ローカル名前空間から名前を削除しましょう。
>>> del C
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'c': <__main__.C object at 0x011BDED0>}
>>> C
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
C
NameError: name 'C' is not defined
それはまさに私たちが期待していることです。名前C
はもはや何にも割り当てられていません。ただし、インスタンスにはまだクラス オブジェクトへの参照があります。
>>> c.__class__
<class '__main__.C'>
>>> id(c.__class__)
18968856
ご覧のとおり、クラスはまだ存在していますC
が、ローカル名前空間の名前から参照することはできません。
という名前の 2 番目のクラスを作成しましょうC
。
>>> class C(object):
greeting = "I'm the second class"
>>> {k:v for k,v, in locals().iteritems() if k[0] != '_'}
{'C': <class '__main__.C'>, 'c': <__main__.C object at 0x011BDED0>}
2 番目のクラスのインスタンスを作成すると、お気付きのように動作します。
>>> c2 = C()
>>> c2.greeting
"I'm the second class"
>>> c.greeting
"I'm the first class"
id
その理由を確認するために、この新しいクラスの を見てみましょう。新しいクラス オブジェクトが最初のオブジェクトとは別の場所に格納されていることがわかります。
>>> id(C)
19011568
>>> id(C) == id(C.__class__)
False
これが、インスタンスが引き続き適切に機能する理由です。両方のクラス オブジェクトが別々に存在し、各インスタンスがそのオブジェクトへの参照を保持します。