2011-05-28 67 views
3

我想创建一个使用对象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"])对于重构和代码完成来说是不好的。

ΤΖΩΤΖΙΟΥ:

I'm certain you don't get anything by using IDs. 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" 

这并不重要,改变一个变量的值,导致因为验证结果一个新的地址后不再有效。

+0

你也可以解释你为什么要使用对象ID吗?到目前为止,我只能看到这个缺点。 – sorin 2011-05-28 07:52:58

+0

@Sorin Sbarnea我添加了一个解释。 – deamon 2011-05-28 09:02:10

+1

我确定你没有通过使用ID得到任何东西。 'obj.field1 = 1;打印(ID(obj.field1)); obj.field1 = 2; print(id(obj.field1))'你知道Python没有变量(如C或Basic),只是这些对象的对象和名称,对不对? – tzot 2011-05-28 09:10:02

回答

4

__getitem__必须返回结果:

def __getitem__(self, key): 
    return super(ObjectIdDict, self).__getitem__(id(key)) 
    #^^^^^ 

没有一个return,隐含的返回值是None,因此oiddict[key] is None所有密钥。

+0

多么愚蠢的错误! ;-) – deamon 2011-05-28 08:05:42