2

我希望能够创建具有从字典动态定义的实例属性的 python 对象。我知道至少有两种方法可以做到这一点,简单地调用setattr(self, k, v)或调用setattr(FooClass, k, property(lambda x: v)). 第一个选项工作得很好,但我不能让第二个做我想做的事。考虑以下代码

class A(object):
    def __init__(self, d):
        for k in d:
            setattr(A, k, property(lambda x: ('Value(%s)' % d[k], 'Key(%s)' % k, d)))

>>> a = A({'foo':'1','bar':'2'})
>>> a.foo
('Value(2)', 'Key(bar)', {'bar': '2', 'foo': '1'})

为什么不a.foo返回foo字典中的值?property对象及其吸气剂是不同的。

>>> A.foo, A.bar
<property at 0x1106c1d60>, <property at 0x1106c1d08>
>>> A.foo.__get__
<method-wrapper '__get__' of property object at 0x1106c1d60>
>>> A.bar.__get__
<method-wrapper '__get__' of property object at 0x1106c1d08>

关于 SO 有很多相关的问题,最好的一个是这个(如何动态地将属性添加到类?)和Eevee答案。不过,这并不能完全解释这种行为。

这些处理类实例上的属性,而不是类Property上的对象

更新

感谢 Martijn Pieters 的帮助(答案)。答案在于 lambda 函数的范围。

>>> A.bar.fget.__closure__[0], A.foo.fget.__closure__[0]
<cell at 0x1106c63d0: dict object at 0x7f90f699fe80>, <cell at 0x1106c63d0: dict object at 0x7f90f699fe80>

工作版本:

class A(object):
    def __init__(self, d):
        for k, v in d.items():
            setattr(A, k, property(lambda x, v=v, k=k: ('Value(%s)' % v, 'Key(%s)' % k, d)))

尽管这实际上修改了类的每个实例以具有相同的属性值。

课:

小心lambda循环内的函数

4

0 回答 0