組み込み関数idは信用できない?
ある日、id関数で遊んでいたら奇妙な現象を発見した。
Python2.7の日本語ドキュメントの言語リファレンス > データモデルから引用すると、
オブジェクトが一度生成されると、そのオブジェクトの アイデンティティ値 は決して変化することがありません;
アイデンティティ値をオブジェクトのメモリ上のアドレスと考えてもかまいません。
演算子 ‘is‘ は、二つのオブジェクト間のアイデンティティ値を比較します;
関数 id() は、オブジェクトのアイデンティティ値を表す整数 (現在の実装ではオブジェクトのメモリ上のアドレス) を返します。
とされている。また、id関数の項目には、
オブジェクトの “識別値” を返します。
この値は整数 (または長整数) で、このオブジェクトの有効期間は一意かつ定数であることが保証されています。
オブジェクトの有効期間が重ならない 2 つのオブジェクトは同じ id() 値を持つかもしれません。
との事。
さて、ここからが本題。上の説明をみると、メモリのアドレス云々はともかく、オブジェクトの識別値を返すんだから
class A(object): def imtd1(self): print 'i1' def imtd2(self): print 'i2'
というクラスAのimtd1とimtd2というインスタンスメソッドは違うオブジェクトだと普通は思う。
だがしかし。この2つはidが同じなのである。
a = A() id(a.imtd1) == id(a.imtd2) # True
幸いなことに?isや==での比較はFalseを返す
a.imtd1 == a.imtd2 # False a.imtd1 is a.imtd2 # False
また、辞書のキーにメソッドを指定している人がいるかもしれないが、その場合にはhashが使われるので大丈夫。
hash(a.imtd1) == hash(a.imtd2) # False
極めつけには、id関数の戻り値が"変わる"。isで比較を行ったあとにもう一度idを呼んでみると
print 'first:', id(a.imtd1) a.imtd1 is a.imtd2 print 'second', id(a.imtd1)
試しにインタプリタで試してみて欲しい(何回か試さないとダメかも)。firstとsecondで変わっているから。
仕様なら仕様でどっかに書いておいて欲しいなあ。
という訳であまり信用出来ないid関数なのでした。