オブジェクトを作成して属性を追加するにはどうすればよいですか?


311

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.attr1obj.a.attr2obj.a.attr3

私が使用しsetattr、私が行う方法を知らなかったので、機能をobj.a.NAMEからforのループ。

p上記の例のの値に基づいて属性をどのように設定しますか?


4
「うまくいかなかった」とはどういう意味ですか?AttributeError例外が発生したと思いますよね?
ジョシュ・ライト

1
ええ。'object'オブジェクトには属性 'somefield'がありません
John

6
なぜあなたはこれをやっている?一般的な「オブジェクト」には実際の意味はありません。あなたが作成しているものの意味は何ですか?なぜそれが適切なクラスまたは名前付きタプルではないのですか?
S.Lott

1
この例は最小限ではなく、私にとって混乱を招くものです。あるいは、なぜあなたが何人かa = object()で作業をせず、あなたが必要とする理由がわかりませんobj.a = object()。ここでも例について話していますが、実際のコードでは、オブジェクト内のオブジェクトが役立つ場合があります。
kon psych 2017

回答:


215

あなたは私の古代を使用することができます 束をレシピをが、「バンチクラス」を作成したくない場合は、非常に単純なものがすでにPythonに存在します。すべての関数は任意の属性(ラムダ関数を含む)を持つことができます。したがって、次の作品:

obj = someobject
obj.a = lambda: None
setattr(obj.a, 'somefield', 'somevalue')

由緒あるBunchレシピと比べて明快さの喪失が問題ないかどうかは、スタイルの決定ですが、もちろんあなたにお任せします。


25
@FogleBird、私が述べたように、スタイルの決定。たとえば教会のラムダ計算で訓練された一部のCSエキスパートは、関数(ラムダ)をすべてのデータの基本的なタイプ(たとえば、整数23はと同等と見なすことができる)と考えることに慣れているため、この目的のためにsをlambda: 23使用するエキスパートにもlambdaおそらく「ハック」のようなものは何もないでしょう。個人的にはlambda 、Pythonはあまり好きはありませんが、それは個人的な好みの問題です。
Alex Martelli、

そして、場合によっては、lambdaパターンがユースケースに適合するかどうかを検討すると、元々データとして考えていたものが実際には関数のようなものであることに気付く場合があります。
カイルストランド2014

5
@ naught101、関数 Pythonではオブジェクトなので、あなたの反対は計り知れません。
Alex Martelli、2015年

6
@ naught101、新しいタイプの作成を回避する(既存のタイプを再利用する)ことは複雑ではなく、単純化します。今日では実際にfrom argparse import Namespace他の場所に住んでほしいと思うかもしれませんが(*例collection)-もう一度、既存のタイプを再利用し、より優れたタイプを使用し、新しいタイプの作成を避けます。しかし、それはそこにありませんでした:-)。
Alex Martelli、2015年

1
タイプモジュールのSimpleNamespaceについては、以下の「JF Sebastian」の回答を参照してください。Pythonのバージョンがサポートしている場合、これが最良のソリューションです(SimpleNamespaceはそのために設計されたものです)
Tim Richardson

334

組み込みはobjectインスタンス化できますが、属性を設定することはできません。(私はそれがこの正確な目的のためにできればいいのにと思います。)それは__dict__属性を保持するためのものを持っていません。

私は通常これを行うだけです:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

可能な場合は、Object入力するデータの種類に応じて、クラスにわかりやすい名前を付けます。

一部の人々は別のことdictを行います。そのサブクラスを使用して、属性アクセスがキーに到達できるようにします。(のd.key代わりにd['key']

編集:質問への追加については、使用しても問題setattrありません。あなただけ使用することはできませんsetattrobject()のインスタンス。

params = ['attr1', 'attr2', 'attr3']
for p in params:
    setattr(obj.a, p, value)

9
それインスタンス化することができますが、一度実行すると、有用なものには使用されません。 foo = object()機能しますが、それを使用してほとんど何もできません
ダニエル・ディパオロ

こんにちは。答えてくれてありがとう。上記の問題を更新しました。編集を参照してください。これに対する答えを知っていますか?
John

申し訳ありませんが、それでもオブジェクトに設定します。上記の更新を参照してください。
ジョン

私はあなたの答えが本当に好きで、私は将来この方向に傾くと思います。この投稿では、この非常にシンプルで理解しやすく、読みやすい方法を除いて、他のすべてについて使用しました。type....コードでのテキストの嘔吐のように、orラムダを使用することは決して私のお気に入りではありませんでした。しかし、このアイデアは、オブジェクトを使用してプロパティを保持するのに最適です。ラムダが表示されたときにコードを読みやすくするb / cのままにします。あなたの方法が完全に理にかなっている間、読み取りを25%に遅くします!ありがとう。
2016年

すばらしい答え、私が変更した唯一のことStructは、それをより明確にするためにクラスの名前として使用することでした。タイピングの手間["を省いてくれて"]、乾杯!
プラグマン

137

types.SimpleNamespacePython 3.3以降にクラスがあります:

obj = someobject
obj.a = SimpleNamespace()
for p in params:
    setattr(obj.a, p, value)
# obj.a.attr1

collections.namedtupletyping.NamedTuple不変オブジェクトに使用できます。PEP 557-Data Classes は、変更可能な代替案を提案しています。

より豊かな機能を実現するには、packageを試してくださいattrs使用例をご覧ください。


3
Python 2.7で動作するものが必要な場合は、argparse.Namespaceクラスを試すこともできます
RolKau

同意します-ここにマイナス面があるかどうか知りたいのですが、これは非常に便利なPython 3.3以降のアフォーダンスです。
ghukill 2017

くそー!これは2.7では利用できませんか?
Roel

@Roel attrsパッケージはPython 2.7をサポート
jfs

これは私にとってunittest.mockよりも良い解決策のようです。後者は少し重すぎるし、少し順応性があります。モックオブジェクトでは、単に属性に割り当てると、属性が存在するようになります。SimpleNamespaceはそれに抵抗します。
jdzions

32

この目標を達成する方法はいくつかあります。基本的に、拡張可能なオブジェクトが必要です。

obj.a = type('Test', (object,), {})  
obj.a.b = 'fun'  

obj.b = lambda:None

class Test:
  pass
obj.c = Test()

14
obj.a = type('', (), {})
iman 2014年

27

mockモジュールは、基本的にはそのために作られています。

import mock
obj = mock.Mock()
obj.a = 5

3
欠点は、それが外部依存性であるということです
Kangur

6
unittest.Mockパイソン3.3(以降標準ライブラリの一部であるdocs.python.org/3/library/unittest.mock.html
illagrenan

2
あなたのコードの使用法に依存すると思います。プロダクションコードの場合、その一部は必要ありませんmock。ただ私に変な感じがします。
Mike de Klerk

21

今、あなたはそれを行うことができます(それがevilpieと同じ答えかどうかはわかりません):

MyObject = type('MyObject', (object,), {})
obj = MyObject()
obj.value = 42

@evilpieの答えは、属性をMyObject(クラス)に直接設定します。自分のインスタンスではありません。
jfs 2015年

18

以下のコードを試してください:

$ 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']

1
これで何ができるのか説明していただけますか?コードはこの問題を解決するのに役立つかもしれませんが、それを説明することで、1つの問題だけでなく、さらに多くのことができるようになります。
DeadChex 2015

1
@DeadChex明らかに、オブジェクトのプロパティを持つ空のクラスである新しいClass(object)を作成し、クラス内に属性を格納します。これは、より多くのモジュールをインストールするか、ラムダに依存するよりも優れています。
m3nda

2
なぜこれ以上の賛成票がないのかわからない。これを基本的なコンテナクラスに使用しない理由はありますか?Python
2.7、2.6

17

クラスオブジェクトを直接使用することもできます。名前空間を作成します:

class a: pass
a.somefield1 = 'somevalue1'
setattr(a, 'somefield2', 'somevalue2')

9

ドキュメントと言います

objectではない持っている__dict__あなたは割り当て、任意でのインスタンスに属性をすることはできませんので、objectクラス。

あなただけのダミークラスのインスタンスを使用することができます。


2

これらのソリューションは、テスト中に非常に役立ちます。他のすべての人の答えに基づいてこれをPython 2.7.9で行います(staticmethodなしでTypeError(unbound method ...)を受け取ります):

In [11]: auth = type('', (), {})
In [12]: auth.func = staticmethod(lambda i: i * 2)
In [13]: auth.func(2)
Out[13]: 4

1

どのオブジェクトを使用していますか?サンプルクラスでそれを試してみましたが、うまくいきました:

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でオブジェクトに属性を追加できないのですか?


bcは定義されたクラスではなくobject()に設定されています
John

0

これは今日の終わりに来ていますが、アプリでいくつかの便利なパスを保持しているオブジェクトを持つ私のペニーワースですが、getattrとドット表記でアクセスできる情報のちょっとした情報が必要なすべての場所に適用できます。 (これは私がこの質問について本当に思っていることです):

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'

したがって、これは上記の回答のように関数オブジェクトを使用しますが、関数を使用して値を取得します(必要に応じて(getattr, x_path, 'repository')ではなく、引き続き使用できx_path('repository')ます)。


0

ネストされたオブジェクトを作成する前に、すべての属性と値を決定して集約できる場合は、作成時に辞書引数を取る新しいクラスを作成できます。

# 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')

-2
di = {}
for x in range(20):
    name = '_id%s' % x
    di[name] = type(name, (object), {})
    setattr(di[name], "attr", "value")

-2

私が見る他の方法、この方法:

import maya.cmds

def getData(objets=None, attrs=None):
    di = {}
    for obj in objets:
        name = str(obj)
        di[name]=[]
        for at in attrs:
            di[name].append(cmds.getAttr(name+'.'+at)[0])
    return di

acns=cmds.ls('L_vest_*_',type='aimConstraint')
attrs=['offset','aimVector','upVector','worldUpVector']

getData(acns,attrs)

名前attr this di [name] .append([at、cmds.getAttr(name + '。' + at)[0]])を追加で追加できます
Pablo Emmanuel De Leo

1
これにより、非常に大きな非標準の依存関係が追加されますが、単純な構成でclass a: passは必要なすべてのパワーが得られます。
Alexis Paques
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.