我想创建一个特殊的字典,使用对象 ID 作为键,如下所示:
class ObjectIdDict(dict):
def __setitem__(self, key, value):
super(ObjectIdDict, self).__setitem__(id(key), value)
def __getitem__(self, key):
super(ObjectIdDict, self).__getitem__(id(key))
但是如果我运行以下测试,则会收到错误:
class ObjectIdDictTest(unittest.TestCase):
def test_get_and_set(self):
dict_to_test = ObjectIdDict()
class Something:
def __init__(self):
self.x = 1
s = Something()
dict_to_test[s.x] = "message"
self.assertEqual(dict_to_test[s.x], "message")
错误信息:
AssertionError: None != 'message'
这里出了什么问题?
背景:
创建如此奇特的字典的原因是我想存储对象的每个字段的验证错误,并希望避免将字段名称作为字符串:
domain_object.errors[domain_object.field1]
,否则将字段名称作为字符串(domain_object.errors["field1"]
)不利于重构和代码完成。
ΤΖΩΤΖιΟΥ:
我确信你不会得到任何东西 使用 ID。
obj.field1= 1; print(id(obj.field1)); obj.field1= 2; print(id(obj.field1))
如果我不使用 ID,则键将是变量的“值”,而不是其地址。如果两个字段具有相同的值,这将导致错误:
def test_ordinary_dict(self):
dict_to_test = {}
class Something:
def __init__(self):
self.x = 1
self.y = 1 # same value as self.x!
s = Something()
dict_to_test[s.x] = "message for x"
dict_to_test[s.y] = "message for y"
self.assertEqual(dict_to_test[s.x], "message for x")
# fails because dict_to_test[s.x] == dict_to_test[1] what results in:
# "message for y"
更改变量值会导致新地址并不重要,因为此后验证结果不再有效。
__getitem__
必须返回结果:
def __getitem__(self, key):
return super(ObjectIdDict, self).__getitem__(id(key))
#^^^^^
如果没有
return
,隐式返回值为
None
,因此所有键都为 oiddict[key] is None
。