[Python] 独自クラスをSetやDictのキーで使えるように、ハッシュ対応する
こんにちは、@yoheiMuneです。
Pythonはやっぱり便利ですね。仕事ではGo言語を使ってますが、プライベートではPythonを使いまくってます。今日は独自クラスをセット型や、辞書型のキーで使う方法をブログに書きたいと思います。
今日はその実装方法をブログに書きました。
上記を実装したUserでは、idが重複するものはSetで1つしか登録できません。
仕様の細かい内容や注意点もありますので、詳細は以下のリンクをご確認ください。
https://docs.python.jp/3/reference/datamodel.html#object.__hash__
最後になりますが本ブログでは、Go言語・Python・Linux・フロントエンド・Node.js・インフラ・開発環境・Swift・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!
Pythonはやっぱり便利ですね。仕事ではGo言語を使ってますが、プライベートではPythonを使いまくってます。今日は独自クラスをセット型や、辞書型のキーで使う方法をブログに書きたいと思います。
目次
独自クラスとSetやDict
今回は、以下のUser
クラスを例に、話を進めていきます。class User(object): def __init__(self, id, name): self.id = id self.name = nameこれをインスタンス化してSetに登録するとエラーなく登録できますが、「同じ」という定義に注意する必要があります。Setでは「同じもの」を1つだけ保持できますが、ここでの「同じ」という定義はメモリ番地で判断されてます。
# インスタンスを作成 user1 = User(1, "Yohei") user2 = User(2, "Satoshi") user3 = User(3, "Kento") user4 = User(1, "Shunji") # idが一緒 # Setを作る s = set([user1, user2, user3, user4]) # 中身を確認する print(len(s)) # 4 print(s) # {<__main__.User object at 0x1021b4898>, <__main__.User object at 0x1021b49e8>, <__main__.User object at 0x1021b4940>, <__main__.User object at 0x1021b4860>}同じく、辞書のキーでも同様に「同じ」定義はメモリ番地が利用されます。
d = dict([(user1, 30), (user4, 25)]) len(d) # 2 print(d) # {<__main__.User object at 0x1021b4860>: 30, <__main__.User object at 0x1021b49e8>: 25}この挙動で問題なければそれでOKなのですが、「同じ」という定義をカスタマイズしたい場合があります。
今日はその実装方法をブログに書きました。
独自クラスでの、Setにおける「同じ」定義をカスタマイズする
「同じ」という定義をカスタマイズするには、__eq__
メソッドと__hash__
メソッドを実装する必要があります。以下の例ではUser
クラスのid
が一致するか否かで、同一判定を実装しました。class User(object): def __init__(self, id, name): self.id = id self.name = name def __eq__(self, other): if not isinstance(other, User): return False return self.id == other.id def __hash__(self): return hash(self.id)公式ドキュメントを読むと分かりますが、「
__eq__
と__hash__
の両方」を実装しないと、同一判定が正しく行われないので注意が必要です。上記を実装したUserでは、idが重複するものはSetで1つしか登録できません。
# インスタンスを作成 user1 = User(1, "Yohei") user2 = User(2, "Satoshi") user3 = User(3, "Kento") user4 = User(1, "Shunji") # idが一緒 # Setを作る s = set([user1, user2, user3, user4]) # 中身を確認する print(len(s)) # 3 for user in s: print(user.id, user.name) # 1 Yohei # 2 Satoshi # 3 Kento辞書のキーでも同様に、idで重複する場合には1つしか登録できません。
d = dict([(user1, 30), (user4, 25)]) len(d) # 1このように、
__eq__
と__hash__
という特殊メソッドを実装することで、独自クラスのハッシュ化の振る舞いを定義することができます。とっても便利ですね。
参考資料
以下の公式ドキュメントを参考に実装を行いました。仕様の細かい内容や注意点もありますので、詳細は以下のリンクをご確認ください。
https://docs.python.jp/3/reference/datamodel.html#object.__hash__
最後に
Pythonは学べば学ぶほど便利に使える言語でいいなーと思います。これからもたくさんPythonネタは書きたいと思いますので、これからもよろしくお願いします。最後になりますが本ブログでは、Go言語・Python・Linux・フロントエンド・Node.js・インフラ・開発環境・Swift・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!