私はPythonで(別のオブジェクトの中に)動的オブジェクトを作成し、それに属性を追加したいです。
私は試した:
obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')
しかしこれはうまくいきませんでした。
何か案は?
編集:
値のリストをループするfor
ループから属性を設定しています。
params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()
for p in params:
obj.a.p # where p comes from for loop variable
上記の例では、私はobj.a.attr1
、obj.a.attr2
、obj.a.attr3
を得ます。
setattr
ループからobj.a.NAME
を実行する方法がわからないため、for
関数を使用しました。
上記の例のp
の値に基づいて属性を設定するにはどうすればよいですか?
私の古くからの バンチ レシピを使うこともできますが、 "バンチクラス"を作りたくないのであれば、非常に単純なものが既にPythonに存在します - - すべての関数は任意の属性(ラムダ関数を含む)を持つことができます。だから、次の作品:
obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')
由緒あるBunch
レシピと比較して明瞭さが失われても大丈夫かどうかは、もちろん私があなたに任せるスタイル決定です。
組み込みのobject
はインスタンス化できますが、属性を設定することはできません。 (この目的のために、できればと思います。)属性を保持するための__dict__
はありません。
私は一般的にこれをするだけです:
class Object(object):
pass
a = Object()
a.somefield = somevalue
可能であれば、どの種類のデータを入れるかに応じて、Object
クラスにわかりやすい名前を付けます。
別のことをする人もいますが、属性へのアクセスを可能にするdict
のサブクラスを使用します。 (d.key
の代わりにd['key']
)
編集:質問に追加するには、setattr
を使用するのが問題ありません。 object()
インスタンスにsetattr
を使うことはできません。
params = ['attr1', 'attr2', 'attr3']
for p in params:
setattr(obj.a, p, value)
Python 3.3には types.SimpleNamespace
クラスがあります+ :
obj = someobject
obj.a = SimpleNamespace()
for p in params:
setattr(obj.a, p, value)
# obj.a.attr1
collections.namedtuple
、 typing.NamedTuple
は、不変オブジェクトに使用できます。 PEP 557 - データクラス は変更可能な代替案を提案しています。
より豊富な機能のためには、 attrs
package を試すことができます。使い方の使用例 を参照してください。
この目標を達成するにはいくつかの方法があります。基本的にあなたは拡張可能なオブジェクトが必要です。
obj.a = type('Test', (object,), {})
obj.a.b = 'fun'
obj.b = lambda:None
class Test:
pass
obj.c = Test()
mock
モジュールは基本的にそのために作られています。
import mock
obj = mock.Mock()
obj.a = 5
今、あなたはすることができます(それが悪と同じ答えであるかどうかわからない):
MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42
以下のコードを試してください。
$ python
>>> class Container(object):
... pass
...
>>> x = Container()
>>> x.a = 10
>>> x.b = 20
>>> x.banana = 100
>>> x.a, x.b, x.banana
(10, 20, 100)
>>> dir(x)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'banana']
クラスオブジェクトを直接使用することもできます。名前空間を作成します。
class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')
注:
object
にはnotが__dict__
があるため、インスタンスに任意の属性を割り当てることはできません。object
クラスの.
あなただけのダミークラスのインスタンスを使用することができます。
これらのソリューションはテスト中に非常に役立ちます。他のみんなの答えを基にして、私はPython 2.7.9でこれを行います(staticメソッドなしでTypeError(unbound method ...)を得ます:
In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4
どのオブジェクトを使っていますか?サンプルクラスでそれを試してみて、それはうまくいきました:
class MyClass:
i = 123456
def f(self):
return "hello world"
b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test
そして私はその答えとして123
を得ました。
私がこの失敗を見る唯一の状況は、あなたが組み込みオブジェクトに対してsetattr
を試みている場合です。
更新日:コメントから、これは繰り返しです: なぜあなたはpythonでオブジェクトに属性を追加することはできませんか?
入れ子になったオブジェクトを作成する前に、すべての属性と値をまとめて決定して集計できれば、作成時に辞書の引数を取る新しいクラスを作成できます。
# python 2.7
class NestedObject():
def __init__(self, initial_attrs):
for key in initial_attrs:
setattr(self, key, initial_attrs[key])
obj = someobject
attributes = { 'attr1': 'val1', 'attr2': 'val2', 'attr3': 'val3' }
obj.a = NestedObject(attributes)
>>> obj.a.attr1
'val1'
>>> obj.a.attr2
'val2'
>>> obj.a.attr3
'val3'
キーワード引数を許可することもできます。この投稿を参照してください。
class NestedObject(object):
def __init__(self, *initial_attrs, **kwargs):
for dictionary in initial_attrs:
for key in dictionary:
setattr(self, key, dictionary[key])
for key in kwargs:
setattr(self, key, kwargs[key])
obj.a = NestedObject(attr1='val1', attr2='val2', attr3= 'val3')
この日遅くにやってくるが、ここに私のペニーワースがあります。それはたまたまアプリの中で役に立つパスをいくつか持っているオブジェクトです。 (これは私がこの問題について本当に考えていることです):
import os
def x_path(path_name):
return getattr(x_path, path_name)
x_path.root = '/home/x'
for name in ['repository', 'caches', 'projects']:
setattr(x_path, name, os.path.join(x_path.root, name))
これはクールだ。
In [1]: x_path.projects
Out[1]: '/home/x/projects'
In [2]: x_path('caches')
Out[2]: '/home/x/caches'
そのため、これは上記の回答のように関数オブジェクトを使用しますが、値を取得するために関数を使用します(必要に応じて、x_path('repository')
ではなく(getattr, x_path, 'repository')
を使用することもできます)。