【问题标题】:Setter of a property used in a dictionary字典中使用的属性的设置器
【发布时间】:2013-07-04 17:40:02
【问题描述】:

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

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 让事情变得更加清晰:如果我理解正确的话,字典中存储的不是具有bar 属性的对象Foo,而是getter 的返回值。对吧?

【问题讨论】:

    标签: python properties


    【解决方案1】:

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

    在不改变您使用对象/字典的方式的情况下,没有真正的方法可以创建这样的链接。也就是说,没有办法创建一个普通的字典,以便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
    

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

    【讨论】:

    • 我试图解决的问题是:我有一个需要修改属性的对象列表。我将它们全部放在字典中,以便轻松访问它们。我现在使用了一个简单的 if/else 构造,它不是那么简洁但可以工作:-)
    【解决方案2】:

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

    >>> 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 永远不会被调用。

    【讨论】:

    • 感谢您对 getter 和 setter 的补充说明。
    猜你喜欢
    • 1970-01-01
    • 2013-09-23
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多