2011-05-28 68 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