为什么python允许元组作为字典的关键

时间:2015-02-08 06:48:29

标签: python dictionary tuples immutability

python中的元组可以包含不同类型的元素。例如:

tup1 = ('physics', 'chemistry', 1997, 2000);
tup2 = (1, 2, 3, 4 );

当用于字典中的键时,python如何在元素大小变化时决定键的大小?

3 个答案:

答案 0 :(得分:4)

Python词典无需知道密钥的大小。 Python字典如果提供__hash____eq__特殊方法,则接受任何对象作为键。 Python通过key == another找到匹配的密钥,内部调用key.__eq__(another)。这也意味着,您可以拥有一个字符串,其中包含字符串,整数,1和100个元素的元组作为键。

为了加快速度,字典将这些密钥组织到一个哈希表中,该哈希表使用用hash(key)计算的哈希码来划分密钥;内部hash(key)来电key.__hash__();哈希码是一个满足两个规则的简单整数:

  1. 必须是hash(key) == hash(another) if key == another
  2. 应该选择哈希密钥,以便key != another最好(但不是在每种情况下)hash(key) != hash(another)
  3. 此外,Python hash(x)必须在x的生命周期内保持不变,这意味着x与其他对象的相等性也不得更改。

    元组同时包含__eq____hash__

    >>> t = ('physics', 'chemistry', 1997, 2000)
    >>> hash(t)
    1710411284653490310
    >>> u = ('physics', 'chemistry', 1997, 2000) # another tuple
    >>> t is u  # they are not the same object
    False
    >>> hash(t) == hash(u)
    True
    >>> t == u
    True
    

    现在,Python甚至根本不需要使用哈希代码来查找字典中的对象,只需找到一个具有匹配键的元素,将每个键与==的给定键进行比较。但这意味着在具有n个密钥的字典中,平均n / 2必须进行比较才能找到密钥。使用散列技巧,我们可以缩小要比较的键集,理想情况下总是最多1或少数,因此字典中的查找应该同样快,无论它是小还是大。


    现在,与元组不同,Python中的list是一个可变值,对于它来说,不可能提供一个不变的哈希码,以后将满足上面给出的2个规则。因此Python根本没有定义它:

    >>> [].__hash__ is None
    True
    

    同样,如果将其用作字典键,则会出现异常:

    >>> {[]: 42}
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unhashable type: 'list'
    

答案 1 :(得分:3)

  

当元素大小变化时,python如何决定键的大小?

简单的答案是它没有:Python允许使用异构密钥的字典。这比不同大小的元组要广泛得多:

In [15]: d = {}

In [16]: d[42] = 'foo'

In [17]: d['bar'] = -1

In [18]: d[(1, 2, 3)] = {}

In [19]: d
Out[19]: {42: 'foo', 'bar': -1, (1, 2, 3): {}}

任何hashable对象,无论其类型如何,都可以用作任何字典的键。

答案 2 :(得分:1)

密钥的大小对字典无关紧要。

字典键必须是不可变的。 由于元组是不可变的,因此可以使用元组作为字典的键。

Source