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

后端 未结 4 1310
刺人心
刺人心 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:02

    What you are seeing is python coercing the 1 to be equal to the True.

    You'll see that the dictionary you print is:

    False  1
    True   a
    2      b
    

    Where the value a was meant to be assigned to the 1, but instead the value for True got reassigned to a.

    According to the Python 3 Documentation:

    The Boolean type is a subtype of the integer type, and Boolean values behave like the values 0 and 1, respectively, in almost all contexts, the exception being that when converted to a string, the strings "False" or "True" are returned, respectively.

    Emphasis mine.

    Note: In python 2.X True and False can be re-assigned, so this behavior cannot be guaranteed.

    0 讨论(0)
  • 2021-01-17 08:11

    This happens because True == 1 (and False == 0, but you didn't have 0 as a key). You'll have to refactor your code or data somehow, because a dict considers keys to be the same if they are "equal" (rather than is).

    0 讨论(0)
  • 2021-01-17 08:15

    Python take the 1 as True. And the Boolean type is a subtype of the integer type

    In [1]: a = {}
    
    In [2]: a[True] = 0
    
    In [3]: 1 in a.keys()
    Out[3]: True
    
    0 讨论(0)
  • 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.

    0 讨论(0)
提交回复
热议问题