7

私はPythonの初心者です。Python Tutorial Release 2.7.5のいくつかの章を読んだ後、Python のスコープと名前空間について混乱しました。何を検索すればよいかわからないため、この質問は重複している可能性があります。

クラスとインスタンスを作成しました。次に、を使用してクラスを削除しましたdel。ただし、インスタンスは引き続き正常に動作します。なんで?

>>>class MyClass:    # define a class
...    def greet(self):
...        print 'hello'
...
>>>instan = MyClass()    # create an instantiation
>>>instan
<__main__.MyClass instance at 0x00BBCDC8>
>>>instan.greet()
hello
>>>dir()
['instan', 'MyClass', '__builtins__', '__doc__', '__name__', '__package__']
>>>
>>>
>>>del MyClass
>>>dir()
['instan', '__builtins__', '__doc__', '__name__', '__package__']
>>>instan
<__main__.MyClass instance at 0x00BBCDC8>    # Myclass doesn't exist!
>>>instan.greet()
hello  

私は OOP についてほとんど知らないので、この質問は単純に思えるかもしれません。前もって感謝します。

4

3 に答える 3

9

Python はガベージ コレクション言語です。実行するとdel MyClass、実際には「クラス オブジェクト」は削除されませんが (クラスもオブジェクトです)、MyClass現在のネームスペースから「名前」のみが削除されます。これは、クラス オブジェクトへの何らかの参照です。オブジェクトは、何かによって参照されている限り存続します。インスタンスは独自のクラスを参照するため、少なくとも 1 つのインスタンスが生きている限り、クラスは生き続けます。

注意すべきことの 1 つは、(コマンド ラインなどで) クラスを再定義する場合です。

In [1]: class C(object):
   ...:     def hello(self):
   ...:         print 'I am an instance of the old class'
In [2]: c = C()
In [3]: c.hello()
I am an instance of the old class
In [4]: class C(object):  # define new class and point C to it
   ...:     def hello(self):
   ...:         print 'I am an instance of the new class'
In [5]: c.hello()  # the old object does not magically become a new one
I am an instance of the old class
In [6]: c = C()  # point c to new object, old class and object are now garbage
In [7]: c.hello()
I am an instance of the new class

古いクラスの既存のインスタンスは、引き続き古い動作を持ちます。これは、私が言及したことを考えると理にかなっています。名前空間とオブジェクトの関係は python 特有のものですが、一度理解すればそれほど難しいことではありません。ここに良い説明があります

于 2013-09-18T10:08:16.020 に答える
3

を使用して変数を削除すると、オブジェクト自体ではなく、変数名delと変数内のオブジェクトへの独自の参照が削除されます。

作成したオブジェクトには、クラスへの独自の参照がまだ含まれています。一般に、誰かが任意のオブジェクト (クラス定義を含む) への参照を保持している限り、ガベージ コレクターによって削除されることはありません。

于 2013-09-18T10:09:31.060 に答える
1

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

これが、インスタンスが引き続き適切に機能する理由です。両方のクラス オブジェクトが別々に存在し、各インスタンスがそのオブジェクトへの参照を保持します。

于 2013-09-18T12:36:18.153 に答える