我可以使用对象(类的实例)作为 Python 中的字典键吗?

Posted

技术标签:

【中文标题】我可以使用对象(类的实例)作为 Python 中的字典键吗?【英文标题】:Can I use an object (an instance of a class) as a dictionary key in Python? 【发布时间】:2011-11-25 11:41:25 【问题描述】:

我想使用类实例作为字典键,例如:

classinstance = class()
dictionary[classinstance] = 'hello world'

Python 似乎无法将类作为字典键处理,还是我错了? 此外,我可以使用像 [(classinstance, helloworld),...] 这样的元组列表来代替字典,但这看起来很不专业。 你有任何解决这个问题的线索吗?

【问题讨论】:

没问题 - 它对我来说很好用。为什么你认为它不起作用 - 你有任何例外吗?你有什么python版本? 我使用 Python 2.7 + twisted 框架。此消息显示在我身上:exceptions.KeyError: <__main__.xmpp instance at> 所以 - 我有信心(或者只是这么认为)这个异常不是在你将元素添加到 dict 时引发的(就像在你的例子中一样)但是当你尝试获取它时 - 检查你放了什么在它之前 - 您用作键的实例可能已更改。 是的,它似乎发生了,我想删除它。正在检查一些细节... 当我尝试获取它时也会发生这种情况。 【参考方案1】:

您的实例需要是可散列的。 python glossary 告诉我们:

如果一个对象的哈希值在其生命周期内永远不会改变(它需要__hash__() 方法),并且可以与其他对象进行比较(它需要__eq__()__cmp__() 方法),则它是可哈希的。比较相等的可散列对象必须具有相同的散列值。

哈希性使对象可用作字典键和集合成员,因为这些数据结构在内部使用哈希值。

所有 Python 的不可变内置对象都是可散列的,而没有可变容器(例如列表或字典)是可散列的。默认情况下,作为用户定义类实例的对象是可散列的;它们都比较不相等,它们的hash值就是它们的id()。

【讨论】:

这是正确的,但具有误导性。默认情况下,所有对象实例都是可散列的。哈希码将是对象实例的唯一标识符。 "他们的哈希值是他们的 id()。"这在 python3.x 之后发生了变化,请参阅 ***.com/a/11324771/2135504【参考方案2】:

尝试在您的类中实现 hasheq 方法。

例如,这是我制作的一个简单的可散列字典类:

class hashable_dict:
    def __init__(self, d):
        self.my_dict = d
        self.my_frozenset = frozenset(d.items())
    def __getitem__(self, item):
        return self.my_dict[item]
    def __hash__(self):
        return hash(self.my_frozenset)
    def __eq__(self, rhs):
        return isinstance(rhs, hashable_dict) and self.my_frozenset == rhs.my_frozenset
    def __ne__(self, rhs):
       return not self == rhs
    def __str__(self):
        return 'hashable_dict(' + str(self.my_dict) + ')'
    def __repr__(self):
        return self.__str__()

【讨论】:

KISS : 保持简单 S* :-) 我认为 ltsstar 不需要这种复杂的代码。 我不同意。我认为编写一个放入字典的类的示例可能非常有用。对于初学者来说,字典似乎很神奇,理解为什么对象会以相同/不同的方式散列对象以确保您的代码按预期工作非常重要。你和我可能只是有不同的个人品味,但我总是喜欢例子,尤其是在 15 行左右的时候。 :)【参考方案3】:

使用实例作为字典键没有任何问题,只要它遵循the rules:字典键必须是不可变的。

【讨论】:

同样的问题,最好用元组什么的? 很难说元组更好。元组更简单。但是,如果您需要将实例存储为字典键,那可能对您更好,但也更复杂。 :)【参考方案4】:

以下代码运行良好,因为默认情况下,您的类对象是可散列的:

Class Foo(object):
    def __init__(self):
        pass

myinstance = Foo()
mydict = myinstance : 'Hello world'

print mydict[myinstance]

输出: 世界你好

另外和更高级的用法,你应该阅读这篇文章:

Object of custom type as dictionary key

【讨论】:

以上是关于我可以使用对象(类的实例)作为 Python 中的字典键吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python中的魔法函数总结整理

类变量实例变量--python

python之面向对象

python中的类的创建使用和继承

基于原型与基于类的继承

python中的面相对象