为什么不能使用不可用类型的内存地址作为dict的键?

时间:2017-08-03 04:24:54

标签: python python-2.7 python-3.x

据我所知,由于像列表这样的不可用类型是变异的,因此不能将它们用作散列的密钥。但是,我不明白为什么他们的记忆地址(我不相信变化)可以使用?

例如:

my_list = [1,2,3]
my_dict = {my_list: 1} #error
my_dict = {id(my_list): 1} # no error

1 个答案:

答案 0 :(得分:1)

如果你扩展listset等,你实际上可以使用对象的内存地址作为哈希函数。

使用哈希的内存地址的主要原因是错误的是因为如果两个对象相等(a == b求值为True),我们也希望它们的哈希值相等(hash(a) == hash(b)True)。否则,我们可能会出现意想不到的行为。

要查看此示例,请创建我们自己的扩展list的类,并使用该对象的内存地址作为哈希函数。

>>> class HashableList(list):
        def __hash__(self):
            return id(self)  # Returns the memory address of the object

现在我们可以创建两个可清除的列表!我们的HashableList使用与python的内置列表相同的构造函数。

>>> a = HashableList((1, 2, 3))
>>> b = HashableList((1, 2, 3))

果然,正如我们所料,我们得到了

>>> a == b
True

我们可以列出我们的列表!

>>> hash(a)
1728723187976
>>> hash(b)
1728723187816
>>> hash(a) == hash(b)
False

如果查看最后3位数字,您会看到ab在内存中相互靠近,但不在同一位置。由于我们使用内存地址作为哈希值,这也意味着它们的哈希值不相等。

如果比较两个相等元组(或任何其他可哈希对象)的内置哈希值会发生什么?

>>> y = ('foo', 'bar')
>>> z = ('foo', 'bar')
>>> y == z
True
>>> hash(y)
-1256824942587948134
>>> hash(z)
-1256824942587948134
>>> hash(y) == hash(z)
True

如果您自己尝试此操作,则('foo', 'bar')的哈希值与我的匹配不匹配,因为每次新的python会话开始时字符串的哈希值都会更改。重要的是,在同一会话中,hash(y)将始终等于hash(z)

让我们看看如果我们制作一个集合会发生什么,并使用HashableList个对象和我们制作的元组。

>>> s = set()
>>> s.add(a)
>>> s.add(y)
>>> s
{[1, 2, 3], ('foo', 'bar')}

>>> a in s  # Since hash(a) == hash(a), we can find a in our set
True
>>> y in s  # Since hash(y) == hash(y), we can find y in our set
True
>>> b in s
False
>>> z in s
True

即使a == b,我们也无法在集合中找到a因为hash(b)不等于hash(a),所以我们无法在 List<Product> prodata = new List<Product>(); RootObject _rootObject = new RootObject(); var list = db.productGetData().ToList(); foreach (var listdata in list) { var _listOfProperties = new List<Property>(); //if product list contains data of properties foreach(var _prop in listdata.Properies) { var property = new Property(); property.PropertyKey = _prop.PropertyKey; property.PropertyValue = _prop.PropertyValue; _listOfProperties.Add(property); } Product pdata = new Product(); pdata.Properties = _listOfProperties; prodata.Add(pdata); } _rootObject.Products = prodata; and now serialize it string stringData = JsonConvert.SerializeObject(_rootObject); 找到{{1}}。在集合中找到我们的等效列表!