在字典中使用的属性的setter

时间:2013-07-04 17:40:03

标签: python properties

我有一个类,有这样的属性:

class Foo(object):
    def __init__(self):
        self._bar = 'bar'

    @property
    def bar(self):
        return self._bar

    @bar.setter
    def bar(self, value):
        self._bar = value

我实例化了该类,在字典中使用它并为该属性分配了一个新值,如下所示:

f = Foo()
d = {'x': f.bar}
d['x'] = 'baz'
print d['x'] # prints baz, as expected
print f.bar  # prints bar, not as expected

为什么我以这种方式使用属性的setter时没有调用它?

编辑:这个visualization使事情变得更加清晰:如果我理解正确,字典中存储的内容不是具有属性的对象Foo { {1}},但是getter的返回值。正确?

2 个答案:

答案 0 :(得分:3)

执行d = {'x': f.bar}时,您将dict的'x'值设置为当前值f.bar ---您创建dict时的值。每次读取dict值时,它都不会创建读取f.bar的“链接”或引用(或者每次设置dict值时都设置它)。对象属性值和dict值之间没有链接。 (这基本上就是你在编辑中所说的:dict中存储的是f.bar;该值并不“知道”它是由readng {{获得的1}},因此它与f.bar的任何未来更改分离。)

如果不改变使用对象/字典的方式,就没有真正的方法来创建这样的链接。也就是说,没有办法创建一个简单的字典,以便f.bar实际上d['x'] = 2。您可以创建一个自定义代理对象类来执行此操作,并使用它而不是dict。或者你可以让dict保存属性名称,并使用f.bar = 2 / getattr来读取/设置值:

setattr

从您的问题中不清楚您的代码的更大目标是什么,因此很难说适当的解决方案是什么。

答案 1 :(得分:1)

当两次使用相同的键时,字典会覆盖它们的值。

>>> test_dict = {'a': 1, 'b': 2, 'c': 3}
>>> test_dict['a'] 
1
>>> test_dict['a'] = 5
>>> test_dict
{'a': 5, 'c': 3, 'b': 2}

在您的代码中

f = Foo()
d = {'x': f.bar} # map 'x' to f.bar - and your getter property is invoked
d['x'] = 'baz'  # remap 'x' to baz
print d['x'] # prints baz, as expected
print f.bar  # prints bar, again getter is invoked here

修改

如果我理解正确,字典中存储的内容不是具有属性栏的对象Foo,而是getter的返回值。对吗?

是的,可以使用getter执行某些操作。例如,假设您需要带有首字母大写字母的栏,您可以修改您的数据并将其返回到getter中。

@property
def bar(self):
    return self._bar.capitalize() 

类似的setter可用于健全性测试。假设您不需要将名为'stupid'的字符串存储在您的数据中 - 您可以执行类似

的操作
@bar.setter
def bar(self, value):
    if value == 'stupid':
        raise ValueError("Stupid not allowed!")
    self._bar = value

基本上,您需要记住的是,当设置值时,将调用setter,并且在检索值时,将调用getter。但是,在您的代码中,永远不会调用setter