8

Python で辞書のキー値としてオブジェクトを使用しようとしています。2 つの機能を実装する必要があるという他の投稿の推奨事項に従います__hash____eq__

それで、私は次のことがうまくいくことを期待していますが、うまくいきませんでした。

class Test:
    def __init__(self, name):
        self.name = name
        
    def __hash__(self):
        return hash(str(self.name))
        
    def __eq__(self, other):
        return str(self.name) == str(other,name)
        
        
def TestMethod():
    test_Dict = {}
    
    obj = Test('abc')
    test_Dict[obj] = obj
    
    print "%s" %(test_Dict[hash(str('abc'))].name)       # expecting this to print "abc" 

しかし、それは私に重要なエラーメッセージを与えています:

KeyError: 1453079729188098211
4

3 に答える 3

15

オブジェクトを再定義hashして辞書キーとして使用する必要はありません。eq

class Test:
    def __init__(self, name):
        self.name = name

test_Dict = {}

obj = Test('abc')
test_Dict[obj] = obj

print test_Dict[obj].name

これは正常に動作し、 print abc. Ignacio Vazquez-Abrams で説明されているように、オブジェクトのハッシュを使用するのではなく、オブジェクト自体をキーとして使用して辞書の値にアクセスします。


あなたが見つけた例はpython: my classes as dict keys のようです。どうやって?またはディクショナリ キーの再定義hashおよびeq特定の目的のためのカスタム タイプのオブジェクト。

たとえば、これら 2 つのオブジェクトobj = Test('abc')と を考えてみましょうobj2 = Test('abc')

test_Dict[obj] = obj
print test_Dict[obj2].name

KeyErrorobj と obj2 は同じオブジェクトではないため、例外がスローされます。

class Test:
    def __init__(self, name):
        self.name = name

    def __hash__(self):
        return hash(str(self.name))

    def __eq__(self, other):
        return str(self.name) == str(other.name)

obj = Test('abc')
obj2 = Test('abc')       

test_Dict[obj] = obj
print test_Dict[obj2].name

このプリントabcobjobj2はまだ異なるオブジェクトですが、同じハッシュを持ち、比較すると等しいと評価されます。

于 2013-07-03T10:31:15.460 に答える
5

マッピングの要素は、ハッシュを使用してマッピング内に配置されますが、ハッシュによってアクセスされることはありません。ストレージと検索の両方でインデックスを作成する場合は、同じ値を使用する必要があります。

于 2013-07-03T08:22:39.330 に答える
0

エラーの説明

投稿で提供されているコードを考えると、 AttributeError を受け取る必要があるため、 KeyError を取得する方法が実際にはわかりません (str(other,name)が意図されたタイプミスであったと仮定しますstr(other.name))。AttributeError は、ルックアップ中のキーがオブジェクトではなく int/long である__eq__ため、self の名前を other の名前と比較するときにメソッドから発生します。hash(str('abc'))Test

__hash__dict でキーを検索する場合、実行される最初の操作は、キーのメソッドを使用してキーのハッシュを取得することです。次に、このハッシュの値が dict に存在する場合__eq__、キーのメソッドが呼び出され、見つかった値とキーを比較します。これは、同じハッシュを持つオブジェクトが dict に格納されている場合 (オープン アドレス指定によって)、正しいオブジェクトが取得されるようにするためです。平均して、このルックアップはまだ O(1) です。

hash(str('abc'))これを 1 ステップずつ見ていくと、とのハッシュはobj同じです。では、文字列のハッシュとしてTest定義します。__hash__でルックアップを実行するとtest_Dict[hash(str('abc'))]、実際にはハッシュのハッシュがルックアップされますが、int のハッシュ自体が python であるため、これは問題ありません。

定義したメソッドに従ってこれら 2 つの値__eq__を比較すると、オブジェクトの名前が比較されますが、比較対象の値は int ( hash(str('abc'))) であり、プロパティを持たないnameため、AttributeError が発生します。

解決

hash()まず、このキーはメソッドの 2 番目の引数としても渡されるため、実際の dict 検索を実行するときに呼び出す必要はありません (すべきではありません) __eq__。そう

test_Dict[hash(str('abc'))].name

なるべき

test_Dict[str('abc')].name

あるいは単に

test_Dict['abc'].name

文字列リテラルの呼び出しstr()はあまり意味がないためです。

次に、比較対象__eq__のオブジェクトのタイプを考慮に入れるようにメソッドを編集する必要があります。インスタンスをキーとしてother同じ dict に保存されるものに応じて、これにはさまざまなオプションがあります。Test

  • インスタンスを他の のみ (またはプロパティを持つ任意のオブジェクト)Testと一緒にディクショナリに格納する場合は、現在持っているものを保持できます。Testname

    def __eq__(self, other):
        return str(self.name) == str(other.name)
    

    辞書で比較している他のすべてのキーがタイプTestであり、name.

  • ディクショナリ内のインスタンスを文字列のみと混合する場合は、Python では文字列にプロパティTestがないため、比較するオブジェクトが文字列かどうかを確認する必要があります。name

    def __eq__(self, other):
        if isinstance(other, str):
            return str(self.name) == other
        return str(self.name) == str(other.name)
    
  • Testとその他のタイプのオブジェクトを組み合わせてキーとして使用する場合は、otherオブジェクトnameに比較対象の があるかどうかを確認する必要があります。

    def __eq__(self, other):
        if hasattr(other, "name"):
            return str(self.name) == str(other.name)
        return self.name == other  # Or some other logic since here since I don't know how you want to handle other types of classes.
    

私は最後の2つのファンではありません.Pythonでのダックタイピングに反対するようなものですが、人生には常に例外があります.

于 2016-06-18T22:29:16.113 に答える