2016-02-03 7 views
13

私は、isオペレータがオブジェクトidの等価性をチェックすると思っていました。しかしそれはそうではないようです。 id(a.f)は、Pythonが同じメモリ位置を再利用して自由である、その後gc'dされるように、オブジェクトへの参照はもう評価されたらあなたは、オブジェクトへの他の参照を保持しないよう同じオブジェクトの異なるメソッドが同じ `id`を持つのはなぜですか?

>>> class A(object): 
... def f(): return 1 
... def g(): return 2 
... 
>>> a = A() 
>>> a.f is a.g 
False 
>>> id(a.f) == id(a.g) 
True 

答えて

14

Pythonは同じメモリ位置を再利用しますa.gです。あなたが名前にメソッドを割り当てる場合は、別の動作が表示されます。

# creates a reference to the method f 
In [190]: f = a.f 
# creates a reference to the method g 
In [191]: g = a.g 
# cannot reuse the memory location of f as it is still referenced 
In [192]: id(f) == id(g) 
Out[192]: False 

は、あなたが実際に本当にのみ、上記と同様の動作を確認するために、Fへの参照を格納する必要があります。

In [201]: f = a.f 

In [202]: id(f) == id(a.g) 
Out[202]: False 

あなたはsys.getrefcountまたはgc.gc.get_referrersで参照カウントを見ることができます:

In [2]: import gc 

In [3]: f = a.f 

In [4]: len(gc.get_referrers(a.g)),len(gc.get_referrers(f)) 
Out[4]: (0, 1) 

In [5]: sys.getrefcount(a.g),sys.getrefcount(f) 
Out[5]: (1, 2) 

ので返さカウントは、一般的にあなたが想像するより1高くなっているので、あなたがAGのための1を参照してください唯一の理由がありますgetrefcount()の引数として(一時的な)参照を含みます。 ので、それはゴミを収集し、Pythonは、何のためのメモリ位置を自由に使用することで、すぐにであるそれはあなた自身の例に類似しており、この方法が評価された後、あなたはまだfへの参照を持っているだろう、a.gで参照カウントが0になります。

行動が方法に限定されるものではないことも注目に値するが、それだけではCPythonの実装の詳細ではなく、あなたが今までに頼るべきものである。

In [67]: id([]), id([]) 
Out[67]: (139746946179848, 139746946179848) 

In [73]: id(tuple()),id([]),id([]) 
Out[73]: (139747414818888, 139746946217544, 139746946217544) 

In [74]: id([]),id([]),id([]) 
Out[74]: (139746946182024, 139746946182024, 139746946182024) 

In [75]: id([]),id(tuple()),id([]) 
Out[75]: (139746946186888, 139747414818888, 139746946186888) 

In [76]: id(tuple()),id([]),id(tuple()) 
Out[76]: (139747414818888, 139746946217736, 139747414818888) 
+0

それは空のタプルはシングルトン(実装の詳細)である私の理解です。とにかく空リストの例ほど興味深いわけではありません。 –

4

同じメモリ場所が使用されていますPythonのメソッドa.fa.gは、**重複しない存続時間*を持つ2つのオブジェクトです。したがって、idは、両方で同じIDを返します。詳細については、後で説明します。 is operatorのドキュメントから

演算子であり、オブジェクト識別のためにテストされていない:xがyは 真である場合にはxとyが同じオブジェクトである場合にのみ。ドキュメントから

id

戻るオブジェクトの「アイデンティティ」です。これは、オブジェクト の整数であり、このオブジェクトに対して一意で一定であることが保証されています(有効期間中に の整数)。 寿命が重複しない2つのオブジェクトは、同じid()値を持つ です。

説明: あなたがclass.nameinstance.name経由でメソッドを検索するたびに、メソッドオブジェクトは、新しいが作成されます。 Pythonは、毎回メソッドオブジェクト内で関数をラップするためにdescriptor protocolを使用します。

したがって、id(a.f)またはid(a.g)を検索すると、新しいメソッドオブジェクトが作成されます。

  1. IDをa.fにすると、そのコピーがメモリに作成されます。新しく作成されたメソッドへの参照がないので、このメモリ位置は、それはあなたがa.gのID、そのコピーを取得した後
  2. 今メモリアドレスが再び利用可能です)GCによって回収、id
  3. によって返されますあなたはtruthy IDの比較

グッド欠如を持っている

  • 再びあなたがidを使用して取得同じメモリアドレスで作成されました!

    2

    a.fとa.gは異なるオブジェクトです。
    が演算子であるのは、それらが1つのオブジェクトである場合のみtrueを返します。 しかし、寿命が重複しない2つのオブジェクトは同じid()値を持つことがあります。従ってそれらは異なるアイデンティティを有する

    は、IDオペレータ

    2

    オペレータisチェックオブジェクト識別しない値に対してhereを参照し、この場合、次の2つの別個の機能(オブジェクト)を有します。

    そして、以下の部分について

    Pythonは、実行時にオブジェクトを作成します

    >>> id(a.f) == id(a.g) 
    True 
    

    ので初めてのPythonの試みがa.fa.gのIDを取得するには、定義されており、Pythonのウィキに基づいてされていません存続期間が重複しない2つのオブジェクトは、同じid()値を持つことがあります。この場合、重複しない存続時間を持つオブジェクトa.fa.gは等しいidを持ちます。

    オブジェクトの「同一性」を返します。これは、オブジェクト の整数であり、このオブジェクトに対して一意で一定であることが保証されています(有効期間中に の整数)。生涯が重複しない2つのオブジェクトは、同じid()値を持つ です。

    isオペレータに関するいくつかの余分ノート:

    私は、IS演算子はチェックがPythonでオブジェクトおよびオブジェクトのアイデンティティは、実行時に作成されるだろう、前述のラインに言ったように。しかし、これは整数や文字列のような小さな型では真ではありません。なぜなら、あなたはシングルトンであり、Pythonオブジェクトではないからです。したがって、C言語のようにすぐにメモリに配置されます。

    より良いデモンストレーションのためにあなたは、以下の例を見ることができます:

    >>> 100 is 10*10 
    True 
    >>> 
    >>> 1000 is 10*100 
    False 
    >>> 
    

    と文字列のために:

    >>> 'aaaa'*5 is 'a'*20 
    True 
    >>> 'aaaa'*50 is 'a'*200 
    False 
    
    関連する問題