2012-09-25 135 views
0

我有这个(Py2.7.2)字典值:暴露通过属性

class MyClass(object): 
    def __init__(self, dict_values): 
     self.values = dict_values 
     self.changed_values = {} #this should track changes done to the values{} 
     .... 

我可以这样使用它:

var = MyClass() 
var.values['age'] = 21 
var.changed_values['age'] = 21 

但我想用这样的:

var.age = 21 
print var.changed_values #prints {'age':21} 

我怀疑我可以使用属性来做到这一点,但如何?

UPDATE:

我不知道在设计时的字典内容。它仅在运行时才会被知道。并且它可能不是空的

+1

'changed_values'有什么用?它与“价值”有什么不同?这是给你的吗? – delnan

+0

简单 - 我想看看究竟发生了什么变化。是的,它可以用一个键列表代替,但这不是问题的关键。 – AlexVhr

+0

我的意思是,如何看待'values'的键不适合你?是否从'changed_values'中删除了项目,并且'changed_values'中的值是否从'values'中的当前值改变了? – delnan

回答

1

您可以创建从字典继承的类并重写所需的功能

class D(dict): 
    def __init__(self): 
     self.changed_values = {} 
     self.__initialized = True 

    def __setitem__(self, key, value): 
     self.changed_values[key] = value 
     super(D, self).__setitem__(key, value) 

    def __getattr__(self, item): 
     """Maps values to attributes. 
     Only called if there *isn't* an attribute with this name 
     """ 
     try: 
      return self.__getitem__(item) 
     except KeyError: 
      raise AttributeError(item) 

    def __setattr__(self, item, value): 
     """Maps attributes to values. 
     Only if we are initialised 
     """ 
     if not self.__dict__.has_key('_D__initialized'): # this test allows attributes to be set in the __init__ method 
      return dict.__setattr__(self, item, value) 
     elif self.__dict__.has_key(item):  # any normal attributes are handled normally 
      dict.__setattr__(self, item, value) 
     else: 
      self.__setitem__(item, value) 

a = D() 
a['hi'] = 'hello' 
print a.hi 
print a.changed_values 

a.hi = 'wow' 
print a.hi 
print a.changed_values 

a.test = 'test1' 
print a.test 
print a.changed_values 

输出

>>hello 
>>{'hi': 'hello'} 
>>wow 
>>{'hi': 'wow'} 
>>test1 
>>{'hi': 'wow', 'test': 'test1'} 
+0

这看起来很有趣,谢谢。但是,我想知道问题的最新部分是否可以简化。 – AlexVhr

+0

使用这个实现,你可以像往常一样更改字典内容(如第一个例子)或使用参数(如第三个例子)。因此,顺便更新字典内容 –

+0

的时间和地点并不重要,如果你想拥有某种改变项目的日志,我会建议使用一个元组列表,其中每个元组都是一对(核心价值)。这样,如果值更改两次,您可以看到它。另外,对于可以放置在该结构上的数据没有限制,例如时间,旧值(对于撤消/重做功能而言是好的)... –

0

属性(描述符,真的)只会在监视的属性集有界时起作用。只需在描述符的__set__()方法中将新值删除即可。

如果这组属性是任意的或无界的,那么您需要改写MyClass.__setattr__()

+1

一段代码会很好,谢谢 – AlexVhr

0

可以使用property()内置功能。

这优于重写__getattr____setattr__,如解释here

class MyClass: 

     def __init__(self): 
      self.values = {} 
      self.changed_values = {} 

     def set_age(nr): 
      self.values['age'] = nr 
      self.changed_values['age'] = nr 

     def get_age(): 
      return self.values['age'] 

     age = property(get_age,set_age) 
+0

但在这种情况下,我必须编写“静态”getter和setter。我想要做的是动态创建它们。 – AlexVhr