Python 即使实际设置了键,字典也会在查找时引发KeyError
当我试图打印字典(或其Python 即使实际设置了键,字典也会在查找时引发KeyError,python,python-3.x,class,dictionary,keyerror,Python,Python 3.x,Class,Dictionary,Keyerror,当我试图打印字典(或其\uuuuuuu dict\uuuuu)时,会出现一个KeyError。dict是从MyClass实例到float和int的映射。 共享MyClass的源代码太长 d = dict() d[MyClass()] = 10.023 d[MyClass()] = 1.023 d[MyClass()] = 8 print(d) Out[16]: --------------------------------------------------------------------
\uuuuuuu dict\uuuuu
)时,会出现一个KeyError。dict是从MyClass
实例到float和int的映射。
共享MyClass
的源代码太长
d = dict()
d[MyClass()] = 10.023
d[MyClass()] = 1.023
d[MyClass()] = 8
print(d)
Out[16]: ---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
c:\users\[...]\lib\site-packages\IPython\core\formatters.py in __call__(self, obj)
700 type_pprinters=self.type_printers,
701 deferred_pprinters=self.deferred_printers)
--> 702 printer.pretty(obj)
703 printer.flush()
704 return stream.getvalue()
[...]
618 p.pretty(key)
619 p.text(': ')
--> 620 p.pretty(obj[key])
621 p.end_group(step, end)
622 return inner
KeyError: <MyClass.subclass instance>
尽管在引发错误之前,某些值已正确打印。它似乎很难找到一些特定的键
我觉得这也很奇怪:
In [19]: [a in d for a in d]
Out[19]: [False, True, False, True, False]
最后:
list(d) # works fine, just like d.keys() and d.values()
Out[19]: [<MyClass.subclass instance>,<MyClass.subclass instance>,<MyClass.subclass instance>,...]
d[list(d)[0]] # works fine
Out[20]: 10.023
d[list(d)[1]] # raises KeyError
list(d)[1] in d # returns False
list(d)[0] in d # returns True
list(d)#工作正常,就像d.keys()和d.values()一样
输出[19]:[,,…]
d[list(d)[0]#工作正常
Out[20]:10.023
d[列表(d)[1]#引发关键错误
d#中的列表(d)[1]返回False
d#中的列表(d)[0]返回True
我检查:
-所有键都有不同的散列
-列表(d)不包含重复项
-列表(d)正确查找的实例没有明显差异(有些甚至是同一类的实例)
-列表项
我想不出对这种行为的解释。它直到今天才显现出来。
我最近对包含MyClass
的模块的文件结构做了一些更改。之前:MyClass
与MyClass
定义位于同一文件中的子类。
之后:MyClass
同一目录中单个文件中的子类。
我看不出这会如何影响这些,但谁知道呢。d=dict(MyClass()=10.023,MyClass()=1.023,MyClass()=8)
不是创建dict的正确语法。当我尝试按如下方式运行它时
class A:
pass
d = dict(A() = 10.023, A() = 1.023, A() = 8)
print(d)
我有个例外
d = dict(A() = 10.023, A() = 1.023, A() = 8)
^
SyntaxError: keyword can't be an expression
一个尝试做类似事情的正确例子是,我创建一个元组列表(classobject,value)
,然后将其转换为dict
class A:
pass
d = dict([(A(),10.023), (A(),1.023), (A(),8)])
print(d)
输出将是
{<__main__.A object at 0x103072ba8>: 10.023, <__main__.A object at 0x103072be0>: 1.023, <__main__.A object at 0x103072c88>: 8}
更新:如果我使用更简单的类,您新更新的语法也适用于我
class A:
pass
d = dict()
d[A()] = 10.023
d[A()] = 1.023
d[A()] = 8
print(d)
#{<__main__.A object at 0x101f72be0>: 10.023, <__main__.A object at 0x101f72c88>: 1.023, <__main__.A object at 0x101f7def0>: 8}
for key in d:
print(d[key])
#10.023
#1.023
#8
A类:
通过
d=dict()
d[A()]=10.023
d[A()]=1.023
d[A()]=8
印刷品(d)
#{: 10.023, : 1.023, : 8}
对于输入d:
打印(d[键])
#10.023
#1.023
#8
在正常情况下,这种情况不应发生
但是,您可能会违反字典约定,即键在相等和哈希方面必须是不可变的。因为如果散列改变了,就再也找不到对象了
[……]
字典的键几乎是任意值。不可散列的值,即包含列表、字典或其他可变类型(通过值而不是对象标识进行比较)的值,不能用作键
演示当使用具有依赖于值的哈希函数的可变对象时会发生什么:考虑这个类:
class Test:
def __init__(self, value):
self.value = value
def __hash__(self):
return self.value
还有这个小片段:
>>> t1 = Test(1)
>>> d = {}
>>> d[t1] = 10
>>> t1.value = 2 # t1's hash also changes at this point
>>> d[t1]
KeyError: <__main__.Test object at 0x0000020FCA5AD748>
>t1=测试(1)
>>>d={}
>>>d[t1]=10
>>>t1.value=2#t1的散列在这一点上也会发生变化
>>>d[t1]
关键错误:
这当然过于简化了,但我怀疑在您的代码中会发生类似的情况。我建议您在程序执行过程中监控与
\uuuuuu hash\uuuuu
和\uuuuuuu eq\uuuuu
相关的值的更改。更新了我的答案,如果您遵循我在答案中使用的约定,您显示的所有示例都适用于我,请检查@user3886973?问题中的更新代码也适用于我@user3886973是的!好的。但这是否也解释了在d.keys()方法中所有键如何保持可访问性?这真的让我很困惑。事实上,散列的一个不应该改变的部分正在被改变。臭虫找到了!Thanks@user3886973键值对仍在字典中。只是lookup计算“当前”散列,并将该散列与在字典中插入密钥时计算的散列进行比较。如果这一点发生变化,则查找将失败。在迭代和.keys
过程中,它只返回所有存储的键值对(不考虑散列)。@user3886973我很高兴答案为您指明了正确的方向,并感谢您接受答案。请不要忘记所有你认为有用的答案。
class Test:
def __init__(self, value):
self.value = value
def __hash__(self):
return self.value
>>> t1 = Test(1)
>>> d = {}
>>> d[t1] = 10
>>> t1.value = 2 # t1's hash also changes at this point
>>> d[t1]
KeyError: <__main__.Test object at 0x0000020FCA5AD748>