18

is演算子は、ID のテストに使用されます。

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

bdictとの値について考えてくださいb[a]

の後続のすべてのルックアップは、またはランダムな整数のd[a]いずれかです。KeyError

しかし、特別な方法に関するドキュメントに記載されているように

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

両者の間には関係がありますが、その逆です。

私はここで多くの質問を見て、その答え多く混乱した心を助けましが、私はこれに対する答えを見つけることができませんでした.isid

4

2 に答える 2

22

いいえ、is単純なポインター比較であり、にidキャストされたオブジェクトのアドレスを返すだけlongです。

からceval.c:

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

vここでwは単純に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.)");
于 2013-03-14T00:24:20.827 に答える
17

短い答えは次のとおりです。いいえ、そうではありません。リンク先のドキュメントには次のように書かれています。

オブジェクト IDの演算子isとテスト: は、とが同じオブジェクトである場合にのみ真になります。is notx is yxy

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


なぜ?isand/orをオーバーライドさせることの害は何idですか? 明らかに、ほとんどの場合、それはばかげたことですが、Python では、十分に努力すれば、多くのばかげたことを実行できます。

設計 FAQ および同様のドキュメントには記載されていません。しかし、それは主に、Python やいくつかのより深い標準ライブラリ モジュールのデバッグが容易になるためだと思います。インタプリタ内から、2 つの名前が実際に同じオブジェクトを参照していることを確認したり、出力したりする方法があることを知っているからです。id名前が時間の経過とともに変更されていないことを確認するためなど。それなしでデバッグを想像してみてweakrefくださいpickle


では、「同じオブジェクト」とは正確には何を意味するのでしょうか。まあ、それは通訳次第です。明らかに、同じオブジェクトの 2 つのインスタンスを言語レベルで区別することは不可能である必要があり、おそらくインタープリター レベルでも同様です (特に、ほとんどのインタープリター実装にプラグインするための明確に定義された API があるため)。

主要な実装はすべて、下位レベルの ID の概念に従うことでこれを処理します。CPython はPyObject*ポインターの値を比較し、Jython は Java 参照を同一性比較し、PyPy はisobjectspace オブジェクトに対して実行します…</p>

PyPy sourceを見る価値があります。これは、「x is yiffxyare the same object 」が両方の方向で真であることを必要とします。トップレベルの式は、適切なオブジェクト空間内のx is yオブジェクトが何であれ、 true であり、として実装されている場合に trueです。したがって、レベル Nでは、レベル N-1 の場合と異なります。wxwywy.is_(wx)is_wy is wxx is yy is x


これは、PyPy を使用して、より高いレベルでdunder メソッドにアタッチするだけで、オーバーライドis 可能なPython の方言を簡単に作成できることを意味します。しかし、同じことを行うより簡単な方法があります。is___is__

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

今度はis_(x, y)の代わりに をx is y試してみて、インタープリターを変更するという大変な作業を行う前に (この場合はそれほど難しくなくても) 楽しいトラブルを見つけられるかどうかを確認してください。


それで、何isと関係がありidますか?isの上に実装できますid—たとえば、x is yチェックだけid(x) == id(y)ですか? さて、id:

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

つまり、idオブジェクトの は一意であり、その存続期間中一定であり、x is yそれらが同じオブジェクトである場合は true です。したがって、x is yiff は trueid(x) == id(y)ですよね?

まあ、idあなたが望むものにリバウンドすることができますが、それは に影響を与えることはできませんis. 定義を非常に慎重に作成した場合 ( へのbuiltins参照を破棄するとid、以前存在していた実装がもはや存在すること、または存在する場合に正しく動作することが保証されないことを覚えておいてください…)、上に定義することができisます。のデフォルト実装のid

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


に関して__hash__は、ドキュメントの重要な部分を読み違えています。

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

省略した部分は、これがユーザー定義クラスのインスタンス (再定義しない) にのみ当てはまることを明確にしています__hash__。たとえば、tuple. 要するに、ID はハッシュとは何の関係もありませんが、一部のオブジェクトでは ID が便利なハッシュ値になるという点が異なります。

于 2013-03-14T00:27:08.413 に答える