Python dictionary doesn't have all the keys assigned, or items

后端 未结 4 1333
刺人心
刺人心 2021-01-17 07:44

I created the following dictionary

exDict = {True: 0, False: 1, 1: \'a\', 2: \'b\'}

and when I print exDict.keys(), well, it g

4条回答
  •  长发绾君心
    2021-01-17 08:18

    If you insert a key-value pair in a dict python checks if the key already exists and if it exists it will replace the current value.

    This check does something like this:

    def hash_and_value_equal(key1, key2):
        return hash(key1) == hash(key2) and key1 == key2
    

    So not only must the values be equal but also their hash. Unfortunatly for you True and 1 but also False and 0 will be considered equal keys:

    >>> hash_and_value_equal(0, False)
    True
    
    >>> hash_and_value_equal(1, True)
    True
    

    and therefore they replace the value (but not the key):

    >>> a = {1: 0}
    >>> a[True] = 2
    >>> a
    {1: 2}
    
    >>> a = {False: 0}
    >>> a[0] = 2
    >>> a
    {False: 2}
    

    I've showed the case of adding a key manually but the steps taken are the same when using the dict literal:

    >>> a = {False: 0, 0: 2}
    >>> a
    {False: 2}
    

    or the dict-builtin:

    >>> a = dict(((0, 0), (False, 2)))
    >>> a
    {0: 2}
    

    This can be very important if you write own classes and want to use them as potential keys inside dictionaries. Depending on your implementation of __eq__ and __hash__ these will and won't replace the values of equal but not identical keys:

    class IntContainer(object):
        def __init__(self, value):
            self.value = value
    
        def __eq__(self, other):
            return self.value == other
    
        def __hash__(self):
            # Just offsetting the hash is enough because it also checks equality
            return hash(1 + self.value)
    
    >>> hash_equal(1, IntContainer(1))
    False
    
    >>> hash_equal(2, IntContainer(1))
    False
    

    So these won't replace existing integer keys:

    >>> a = {1: 2, IntContainer(1): 3, 2: 4}
    >>> a
    {1: 2, <__main__.IntContainer at 0x1ee1258fe80>: 3, 2: 4}
    

    or something that is considered as identical key:

    class AnotherIntContainer(IntContainer):
        def __hash__(self):
            # Not offsetted hash (collides with integer)
            return hash(self.value)
    
    >>> hash_and_value_equal(1, AnotherIntContainer(1))
    True
    

    These will now replace the integer keys:

    >>> a = {1: 2, AnotherIntContainer(1): 5}
    >>> a
    {1: 5}
    

    The only really important thing is to keep in mind that dictionary keys are consered equal if the objects and their hash is equal.

提交回复
热议问题