我有一个类,有这样的属性:
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的返回值。正确?
答案 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
。