1

我有一个具有如下属性的类:

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?

编辑:这个可视化让事情变得更加清晰:如果我理解正确的话,字典中存储的不是具有Foo属性的对象bar,而是 getter 的返回值。正确的?

4

2 回答 2

3

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

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

d = {'x': 'bar'}
getattr(f, d['x']) # gives the value of f.bar
setattr(f, d['x'], 2) # sets f.bar = 2

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

于 2013-07-04T17:49:09.343 回答
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 可用于执行某些操作。例如,假设您需要带首字母大写的 bar,您可以修改数据并在 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从未调用过。

于 2013-07-04T17:54:32.673 回答