带有对象ID的特殊Python字典
我想创建一个特别的字典,用对象的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"
改变变量的值导致新的地址并不是关键,因为在那之后验证结果就不再有效了。
1 个回答
4
__getitem__
这个方法必须返回一个结果:
def __getitem__(self, key):
return super(ObjectIdDict, self).__getitem__(id(key))
#^^^^^
如果没有写 return
,那么默认返回的值就是 None
,所以对于所有的键来说,oiddict[key] 的值就是 None
。