当我尝试打印字典(或其__dict__
)时,会引发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>
以下还会引发KeyError:
for key in d:
print(d[key])
尽管在出现错误之前可以正确打印某些值。查找某些特定键似乎有麻烦。
我认为这也很奇怪:
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
我检查了: -所有键都有不同的哈希 -列表(d)不包含重复项 -正确查找的list(d)实例没有明显区别(有些甚至是同一类的实例) -列表项
我想不出对此行为的解释。它直到今天才显现出来。
最近,我对包含MyClass
的模块的文件结构进行了一些更改。之前:MyClass
与MyClass
定义在同一个文件中。
之后:MyClass
属于同一目录中各个文件的子类。
我不知道这会如何影响其中的任何一个,但谁知道。
答案 0 :(得分:1)
在正常情况下,这种情况不会发生。
但是,您可能会违反字典约定,即键必须在相等性和哈希值方面保持不变。因为如果哈希值发生更改,将无法再找到对象。
Mapping Types — dict
[...]
字典的键几乎是任意值。不可散列的值,即包含列表,字典或其他可变类型的值(通过值而不是对象标识进行比较),不能用作键。
要演示当您使用具有依赖于值的哈希函数的可变对象时会发生什么:请考虑此类:
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>
这当然过于简化,但是我怀疑您的代码中会发生类似的事情。我建议您在程序执行期间监视与__hash__
和__eq__
相关的值的更改。
答案 1 :(得分:0)
d = dict(MyClass()=10.023, MyClass()=1.023, MyClass()=8)
不是创建字典的正确语法。当我尝试按以下方式运行
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)
,然后将其转换为字典
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}
还list(d)
为您提供了一个键列表,就像您在示例中已经看到的那样,然后当您执行d[list(d)[0]]
时,您将获得第一个键,然后获得第一个键的值键。
对于最后两个语句,如果您遵循我的命名约定,它们将返回true,同样,您问题中的更新语句也对我有用。
class A:
pass
d = dict([(A(),10.023), (A(),1.023), (A(),8)])
#Print list of keys
print(list(d))
#[<__main__.A object at 0x102a72ba8>, <__main__.A object at 0x102a72be0>, <__main__.A object at 0x102a72c88>]
#Value of first key
print(d[list(d)[0]])
#10.023
#Value of second key
print(d[list(d)[1]])
#1.023
#Checks if second key is present in list of keys, which is True
print(list(d)[1] in d )
#True
#Checks if first key is present in list of keys, which is True
print(list(d)[0] in d )
#True
更新:如果我使用更简单的类,您的新更新语法也对我有用
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