2013-03-14 4 views
7

is演算子は、同一性のテストに使用されます。`is`演算子はPythonで__magic__メソッドを使用していますか?

isオペレータとid()機能は任意の__magic__方法、__eq__を呼び出し==方法を呼び出す場合、私は思っていました。私は__hash__をチェックアウトし、いくつかの楽しみを持っていた

class Foo(object): 
    def __hash__(self): 
     return random.randint(0, 2 ** 32) 

a = Foo() 
b = {} 
for i in range(5000): 
    b[a] = i 

辞書bb[a]

の値について考え

d[a]のすべてのその後の検索がKeyErrorのいずれかでありますまたはランダムな整数です。

しかしdocs on the special methods状態

ようのデフォルト実装] X。 __hash__()はid(x)を返します。

したがって、の関係にありますが、その逆です。

私はここisidに多くのquestionsを見てきた、とanswersは多くのconfused心を支援してきましたが、私はこの1つの答えを見つけることができませんでした。

+0

あなたの例は実際には面白いです。 Favourited that :) – nneonneo

+0

デフォルトの 'hash'の定義は正しくありません。 CPythonでは、 'PyBaseObject_Type.tp_hash'は' long _Py_HashPointer(void * p){long x;}です。 size_t y =(size_t)p; y =(y >> 4)| (y <<(8 * SIZEOF_VOID_P-4)); x =(long)y; if(x == -1)x = -2; return x;} 'これは、アドレスの下位2〜4ビットがおそらく0である場合、ハッシュ衝突を減らすためにアドレスを4ビット回転させます。 – eryksun

答えて

14

いいえ、isはストレートポインタの比較であり、idはキャストオブジェクトのアドレスをlongに返します。 ceval.cから

:ここ

case PyCmp_IS: 
    res = (v == w); 
    break; 
case PyCmp_IS_NOT: 
    res = (v != w); 
    break; 

vwは単にPyObject *あります。 bltinmodule.cから

static PyObject * 
builtin_id(PyObject *self, PyObject *v) 
{ 
    return PyLong_FromVoidPtr(v); 
} 

PyDoc_STRVAR(id_doc, 
"id(object) -> integer\n\ 
\n\ 
Return the identity of an object. This is guaranteed to be unique among\n\ 
simultaneously existing objects. (Hint: it's the object's memory address.)"); 
+2

+1(これはあまりにも怠惰でした;)) –

+2

コード行は1000枚分の価値があります。 –

+0

この回答はCPythonに固有のものです。他の実装(少なくともJythonとPyPy)では、 'is'はポインタ比較ではなく、' id'はアドレスを返しません。 – abarnert

9

短い答えは:いいえ、そうではありません。

オブジェクト識別のための事業者isis notテストを:あなたが言うにリンクドキュメントとしてx is yxyが同じオブジェクトである場合にのみ当てはまります。

「同じオブジェクト」とは、あなたが上書きできるものではありません。あなたのオブジェクトが別のオブジェクトと同じオブジェクトでない場合、そのオブジェクトはふりをすることができません。


だから...なぜ? isおよび/またはidを無効にすることの害は何ですか?明らかに、これはほとんど常に愚かなことですが、Pythonでは十分な努力をすると多くの愚かなことができます。

デザインに関するよくある質問とそれに類する書類には言及していません。しかし、私はそれが主に、Pythonとより深い標準ライブラリモジュールのデバッグを容易にしていると考えています。インタープリタ内から、2つの名前が実際に同じオブジェクトを参照しているかどうかを確認する方法や、 idは時間の経過とともに名前が変更されていないことを確認します。weakref、またはそれ以外の場合はpickleのデバッグを想像してください。


「同じオブジェクト」とはどういう意味ですか?さて、それは通訳者の責任です。明らかに、同じオブジェクトの2つのインスタンスを言語レベルで、おそらくインタープリタレベルでも区別することは不可能でなければなりません(ほとんどのインタープリタ実装にプラグインするための明確なAPIがあるため)。

すべての主な実装では、下位レベルのアイデンティティーの概念に従うことでこれを処理します。 CPythonのはPyObject*ポインタの値を比較し、Jythonのは、アイデンティティ・比較Javaの参照を、PyPyは、オブジェクト・スペースのオブジェクトに関するis ...

それは価値があるが必要ですPyPy source、見てを行う「x IFF x is yyは同じオブジェクトであります"双方向で真実であること。適切なオブジェクト空間内の任意のオブジェクトwxおよびwyが、wy.is_(wx)が真であり、is_wy is wxとして実装されている場合、トップレベル式x is yは真です。従ってレベルNにx is yがある場合、レベルN-1でy is xとなる。


これは、あなたはかなり簡単にisただより高いレベルでdunder方法__is__is_を装着することにより、無効にすることができるのPythonの方言を構築するためにPyPyを使用することを意味していることに注意してください。しかし、同じことを行うための簡単な方法があります:

def is_(x, y): 
    if hasattr(x, '__is__'): 
     return x.__is__(y) 
    elif hasattr(y, '__is__'): 
     return y.__is__(x) 
    else: 
     return x is y 

は今、「それがにISN場合でも(is_(x, y)の代わりx is yと遊ぶ、そしてあなたが通訳を変更するハードワークを行う前に、すべての楽しトラブルを見つけることができるかどうかを確認しますこの場合ハード)。


ので、isidとどんな関係があるのか​​。 isidの上に実装できます。x is yはちょうどid(x) == id(y)をチェックしますか?まあ、id

オブジェクトの「同一性」を返します。これは、そのオブジェクトの存続期間中に一意で定数であることが保証されている整数です。寿命が重複しない2つのオブジェクトの値は同じid()になる場合があります。

ので、オブジェクトのidは、その存続期間中にユニークかつ一定であり、それらが同じオブジェクトだ場合に限っx is yが真である、したがって、x is yは右、真IFF id(x) == id(y)のですか?

まあ、idは、あなたが望むものにリバウンドすることができ、それはisに影響しません。この定義を非常に慎重に作成した場合は、idへの参照を破棄した場合は、それ以上存在することが保証されていない場合でも、存在する場合は正常に動作することも保証されません...)、idの既定の実装の上にisを定義します。

しかし、それは奇妙なことです。 CPythonでは、id(x)は「メモリ内のオブジェクトのアドレスを返す」だけです。メモリ内のオブジェクトへのポインタの値と同じものです。しかし、これは単なるCPythonの成果物です。 idは、ID比較に使用される基になる値を整数として返さなければならないということは他にもありません。実際には、ポインターなしで(整数にキャストできる)言語で書かれたインプリメンテーションでそれをどうやって行うのかは明らかではありません。 PyPyでは、オブジェクトのidは、最初にアクセスされたときに計算された値であってもよいし、オブジェクト自体のキーによってオブジェクト空間の辞書に隠されていてもよい。 __hash__については


、あなたは、ドキュメントの重要な部分を誤読しています。

[...] x.__hash__()id(x)を返します。

省略された部分は、ユーザー定義クラスのインスタンス(__hash__を再定義しない場合)にのみ当てはまることが明らかです。明らかに、たとえばtupleの場合は当てはまりません。要するに、アイデンティティはハッシュとは関係がありませんが、一部のオブジェクトではアイデンティティが便利なハッシュ値になります。

+2

"あなたのオブジェクトが別のオブジェクトと同じオブジェクトでない場合、そのオブジェクトは真似できません。" +1 – mgilson

関連する問題