辞書から動的に定義されたインスタンス属性を持つ python オブジェクトを作成できるようにしたいと考えています。setattr(self, k, v)
これを行うには、単に呼び出すか、代わりに を呼び出す少なくとも 2 つの方法があることを認識していますsetattr(FooClass, k, property(lambda x: v))
。最初のオプションは完全に正常に動作しますが、2 番目のオプションではやりたいことを実行できません。次のコードを検討してください
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 の助けに感謝します ( answer )。答えは、ラムダ関数のスコープにあります。
>>> 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
ループ内の関数には注意してください