Python 3:
>>> from collections import OrderedDict
>>> d1 = OrderedDict([('foo', 'bar')])
>>> d2 = OrderedDict([('foo', 'bar')])
等しいかどうかを確認したい:
>>> d1 == d2
True
>>> d1.keys() == d2.keys()
True
だが:
>>> d1.values() == d2.values()
False
値が等しくない理由を知っていますか?
これをPython 3.4および3.5でテストしました。
この質問に続いて、私はPython-Ideasメーリングリストに投稿して詳細を追加しました:
https://mail.python.org/pipermail/python-ideas/2015-December/037472.html
Python 3、で、dict.keys()
およびdict.values()
は、それぞれcollections.abc.KeysView
およびcollections.abc.ValuesView
の特別な反復可能なクラスを返します。最初の1つはset
から__eq__
メソッドを継承し、2つ目はオブジェクトのIDをテストするデフォルトのobject.__eq__
を使用します。
Python3では、d1.values()
とd2.values()
はcollections.abc.ValuesView
オブジェクトです:
>>> d1.values()
ValuesView(OrderedDict([('foo', 'bar')]))
それらをオブジェクトとして比較しないでください。それらをリストに変換してから比較します。
>>> list(d1.values()) == list(d2.values())
True
キーを比較するために機能する理由を調査します。CPythonの_collections_abc.py
では、KeysView
はSet
から継承していますが、ValuesView
は次のことを行いません:
class KeysView(MappingView, Set):
class ValuesView(MappingView):
ValuesView
とその親の__eq__
のトレース:
MappingView ==> Sized ==> ABCMeta ==> type ==> object
。
__eq__
はobject
にのみ実装され、オーバーライドされません。
一方、KeysView
はSet
から直接__eq__
を継承します。
残念ながら、どちらの現在の回答もこれがなぜなのかについては触れていませんが、これがどのように行われるかに焦点を当てています。メーリングリストでの議論は素晴らしかったので、以下にまとめます。
odict.keys
/dict.keys
およびodict.items
/dict.items
の場合:
odict.keys
( dict.keys
のサブクラスは、collections.abc.Set
(セットのようなオブジェクト)に準拠しているため、比較をサポートしています。これは、ディクショナリ内のkeys
(順序付けされているかどうかにかかわらず)が一意でハッシュ可能であることが保証されているために可能です。odict.items
( dict.items
のサブクラス)も、.keys
と同じ理由で比較をサポートします。 itemsview
は、item
s(具体的には、値を表す2番目の要素)の1つがハッシュ可能でない場合に適切なエラーを発生させるため、これを行うことができますが、一意性は保証されます(keys
は一意です):
>>> od = OrderedDict({'a': []})
>>> set() & od.items()
TypeErrorTraceback (most recent call last)
<ipython-input-41-a5ec053d0eda> in <module>()
----> 1 set() & od.items()
TypeError: unhashable type: 'list'
これらの両方のビューkeys
、items
の比較では、オブジェクトall_contained_in
を使用する __contain__
(かなり読みやすい)と呼ばれる単純な関数を使用します関連するビューの要素のメンバーシップをチェックする方法。
odict.values
/dict.values
について:
気づいたように、odict.values
( dict.values
のサブクラス [shocker])は次のように比較しませんセットのようなオブジェクト。これは、values
のvaluesview
をセットとして表すことができないためです。理由は2つあります。
メーリングリストの @ user2357112 および @ abarnett によるコメントで述べられているように、odict.values
/dict.values
はマルチセットであり、セットの一般化です。その要素の複数のインスタンスを許可します。これらを比較しようとすることは、固有の重複、順序付け、およびこれらの値に対応するキーを考慮する必要があるという事実により、keys
またはitems
を比較するほど簡単ではありません。 dict_values
は次のようになります。
>>> {1:1, 2:1, 3:2}.values()
dict_values([1, 1, 2])
>>> {1:1, 2:1, 10:2}.values()
dict_values([1, 1, 2])
キーに対応する値が同じでなくても、実際には等しいですか?多分?そうでないかもしれない?それはどちらの方法でも簡単ではなく、避けられない混乱を招きます。
ただし、これらをそのままkeys
およびitems
と比較して、要約すると、@ abarnettからの別のコメント mailingリスト :
標準のマルチセットタイプまたはABCがないにもかかわらず、マルチセットが何をすべきかを定義し、それを値ビューに適用できると考えている場合、次の質問は、非ハッシュ可能な2次時間よりも優れた方法でそれを行う方法です。値。 (そして、ここでの順序付けも想定できません。)値ビューを30秒間ハングさせてから、20ミリ秒で間違った答えを返すのではなく、直感的に望んだ答えを返すのは改善でしょうか。 (どちらの方法でも、同じレッスンを学びます。値のビューを比較しないでください。20ミリ秒で学習したいと思います。)