In Python, why is a tuple hashable but not a list?

后端 未结 6 1856
我寻月下人不归
我寻月下人不归 2020-12-14 02:10

Here below when I try to hash a list, it gives me an error but works with a tuple. Guess it has something to do with immutability. Can someone explain this in detail ?

6条回答
  •  温柔的废话
    2020-12-14 02:48

    Here are examples why it might not be a good idea to allow mutable types as keys. This behaviour might be useful in some cases (e.g. using the state of the object as a key rather than the object itself) but it also might lead to suprising results or bugs.

    Python

    It's possible to use a numeric list as a key by defining __hash__ on a subclass of list :

    class MyList(list):
        def __hash__(self):
            return sum(self)
    
    my_list = MyList([1, 2, 3])
    
    my_dict = {my_list: 'a'}
    
    print(my_dict.get(my_list))
    # a
    
    my_list[2] = 4  # __hash__() becomes 7
    print(next(iter(my_dict)))
    # [1, 2, 4]
    print(my_dict.get(my_list))
    # None
    print(my_dict.get(MyList([1,2,3])))
    # None
    
    my_list[0] = 0  # __hash_() is 6 again, but for different elements
    print(next(iter(my_dict)))
    # [0, 2, 4]
    print(my_dict.get(my_list))
    # 'a'
    

    Ruby

    In Ruby, it's allowed to use a list as a key. A Ruby list is called an Array and a dict is a Hash, but the syntax is very similar to Python's :

    my_list = [1]
    my_hash = { my_list => 'a'}
    puts my_hash[my_list]
    #=> 'a'
    

    But if this list is modified, the dict doesn't find the corresponding value any more, even if the key is still in the dict :

    my_list << 2
    
    puts my_list
    #=> [1,2]
    
    puts my_hash.keys.first
    #=> [1,2]
    
    puts my_hash[my_list]
    #=> nil
    

    It's possible to force the dict to calculate the key hashes again :

    my_hash.rehash
    puts my_hash[my_list]
    #=> 'a'
    

提交回复
热议问题