1. ホーム
  2. python

[解決済み] Pythonのデータクラスをイミュータブルにせずにハッシュ化するには?

2023-06-01 17:42:11

質問

Python3でデータクラスを持っているとします。私はこれらのオブジェクトをハッシュし、順序付けることができるようにしたい。私はこれらが不変であることを望んでいない。

私はidで順序付け/ハッシュ化したいだけです。

私はdocsで私がちょうど実装することができることを参照してください_。 ハッシュ _ などと書いてありますが、datacalsesはこれを処理することを目的としているので、その作業をやってもらいたいと思います。

from dataclasses import dataclass, field

@dataclass(eq=True, order=True)
class Category:
    id: str = field(compare=True)
    name: str = field(default="set this in post_init", compare=False)

a = sorted(list(set([ Category(id='x'), Category(id='y')])))

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'Category'

どのように解決するのですか?

から ドキュメント :

の暗黙の生成に関する規則を以下に示します。 __hash__() メソッドの暗黙の生成に関する規則を示します。

[...]

もし eqfrozen は両方とも真で、デフォルトでは dataclass() は を生成します。 __hash__() メソッドを生成します。もし eq が真で frozen は偽です。 __hash__() に設定されます。 None にセットされ、ハッシュ不可能であることを示します。 (に設定され、ハッシュ不可能であることを示します(これはミュータブルであるためです)。もし eq が偽の場合 __hash__() はそのままにされ、つまり __hash__() メソッドが使用されます。 メソッドが使用されます (スーパークラスがオブジェクトの場合、これはつまり はidベースのハッシュにフォールバックすることを意味します)。

を設定したので eq=True を設定し frozen をデフォルトのままにしておきました ( False ) の場合、データクラスはハッシュ不可能になります。

3つのオプションがあります。

  • 設定 frozen=True (さらに eq=True を追加)、これによりクラスがイミュータブルでハッシュ化できるようになります。
  • 設定する unsafe_hash=True を作成します。 __hash__ メソッドを作成しますが、クラスは変更可能なままなので、クラスのインスタンスがdictやsetに格納されている間に変更された場合に問題が発生する危険性があります。

    cat = Category('foo', 'bar')
    categories = {cat}
    cat.id = 'baz'
    
    print(cat in categories)  # False
    
    
  • 手動で __hash__ メソッドを実装します。