【问题标题】:Python dictionary doesn't have all the keys assigned, or itemsPython 字典没有分配所有的键或项
【发布时间】:2016-05-04 03:50:06
【问题描述】:

我创建了以下字典

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

当我打印exDict.keys() 时,它给了我一个生成器。好的,所以我将它强制到一个列表中,它给了我

[False, True, 2]

为什么没有 1?当我打印 exDict.items() 它给了我

[(False, 1), (True, 'a'), (2, 'b')]

有人猜到这里发生了什么吗?我被难住了。

【问题讨论】:

  • 不错的抓挠者! Python 的设计者尽量避免意外,但你不可能全部都得到......
  • 您的项目中有解决方案:(True, 'a'),这是1 的值。

标签: python dictionary


【解决方案1】:

这是因为True == 1(和False == 0,但您没有0 作为密钥)。您必须以某种方式重构您的代码或数据,因为 dict 认为如果键“相等”(而不是 is),则它们是相同的。

【讨论】:

  • 我不确定是否有确定性。反正我不会依赖它。
  • @heemayl 即使不能保证 dict 中项目的顺序,我认为它使用的键将是第一个遇到的键。当它找到一个等效的现有密钥时,它不会替换密钥。
  • @heemayl :与 Mark Ransom 的建议相反,在当前 2.7.x 和 3.x 中,最终值是 last 遇到的等效键(在您的示例中它是a) 。这也是有道理的,如果我们认为字典可能是从字面量迭代构造的,那么“较晚”的映射会覆盖“较早”的映射。
  • 我希望 dict 文字中相同键的多个实例导致运行时错误。
  • @mikołak,我不是在谈论 value,我是在谈论 key。我刚刚测试了 Python 2.7.10,它按我说的方式工作,保留了原始密钥。它也可以按照您所说的方式工作,保留最后一个值。
【解决方案2】:

您看到的是 python 强制 1 等于 True

你会看到你打印的字典是:

False  1
True   a
2      b

a 的值原本应该分配给 1,但 True 的值却被重新分配给了 a

根据Python 3 Documentation

布尔类型是整数类型的子类型,布尔值在几乎所有上下文中的行为分别类似于值 0 和 1,但在转换为字符串时除外,分别返回字符串“False”或“True”。

强调我的。

注意:在 python 2.X 中,TrueFalse 可以重新分配,因此无法保证这种行为。

【讨论】:

    【解决方案3】:

    Python 将 1 作为True。而布尔类型是整数类型的子类型

    In [1]: a = {}
    
    In [2]: a[True] = 0
    
    In [3]: 1 in a.keys()
    Out[3]: True
    

    【讨论】:

      【解决方案4】:

      如果您在dict 中插入键值对,python 会检查该键是否已存在,如果存在,它将替换当前值。

      这个检查是这样的:

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

      因此不仅值必须相等,而且它们的hash 也必须相等。不幸的是,True1 以及 False0 将被视为相同的键:

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

      因此它们替换了值(不是键):

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

      我已经展示了手动添加密钥的情况,但是使用dict literal时所采取的步骤是相同的​​:

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

      dict-builtin:

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

      如果您编写自己的类并希望将它们用作字典中的潜在键,这可能非常重要。根据您对 __eq____hash__ 的实现,它们将替换也不会替换相等但不相同的键的值:

      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
      

      所以这些不会替换现有的整数键:

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

      或被视为相同密钥的东西:

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

      这些现在将替换整数键:

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

      唯一真正重要的是要记住,如果对象及其哈希值相等,则字典键是相等的。

      【讨论】:

        猜你喜欢
        • 2018-05-16
        • 1970-01-01
        • 2017-06-05
        • 2021-12-27
        • 1970-01-01
        • 2023-03-10
        • 1970-01-01
        • 2016-05-27
        • 1970-01-01
        相关资源
        最近更新 更多