433 Stimmen

Wie kann ich ein Objekt erstellen und ihm Attribute hinzufügen?

Ich möchte ein dynamisches Objekt (innerhalb eines anderen Objekts) in Python erstellen und ihm dann Attribute hinzufügen.

Ich habe es versucht:

obj = someobject
obj.a = object()
setattr(obj.a, 'somefield', 'somevalue')

aber das hat nicht funktioniert.

Irgendwelche Ideen?

bearbeiten:

Ich setze die Attribute aus einer for Schleife, in der eine Liste von Werten durchlaufen wird, z. B.

params = ['attr1', 'attr2', 'attr3']
obj = someobject
obj.a = object()

for p in params:
   obj.a.p # where p comes from for loop variable

In dem obigen Beispiel würde ich Folgendes erhalten obj.a.attr1 , obj.a.attr2 , obj.a.attr3 .

Ich habe die setattr Funktion, weil ich nicht wusste, wie man die obj.a.NAME von einer for Schleife.

Wie würde ich das Attribut auf der Grundlage des Wertes von p im obigen Beispiel?

462voto

FogleBird Punkte 69852

Die eingebaute object kann instanziiert werden, aber es können keine Attribute für sie festgelegt werden. (Ich wünschte, es könnte, für genau diesen Zweck.) Es hat keine __dict__ um die Attribute zu speichern.

Im Allgemeinen mache ich das einfach:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

Wenn ich kann, gebe ich die Object Klasse einen aussagekräftigeren Namen geben, je nachdem, welche Art von Daten ich darin speichern möchte.

Manche Leute machen es anders, sie verwenden eine Unterklasse von dict die den Zugriff auf die Schlüssel über Attribute ermöglicht. ( d.key anstelle von d['key'] )

Editar : Um Ihre Frage zu beantworten, sollten Sie setattr ist in Ordnung. Sie können nur nicht verwenden setattr en object() Instanzen.

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

265voto

Alex Martelli Punkte 805329

Du könntest meine alte Bündel Rezept, aber wenn Sie keine "Bündelklasse" erstellen wollen, gibt es in Python bereits eine sehr einfache - alle Funktionen können beliebige Attribute haben (einschließlich Lambda-Funktionen). Also, das Folgende funktioniert:

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

Ob der Verlust an Klarheit im Vergleich zu den altehrwürdigen Bunch Rezept ist OK, ist eine Stilentscheidung, die ich natürlich Ihnen überlasse.

188voto

jfs Punkte 370717

Es gibt types.SimpleNamespace Klasse in Python 3.3+ :

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

collections.namedtuple , typing.NamedTuple könnte für unveränderliche Objekte verwendet werden. PEP 557 -- Datenklassen schlägt eine veränderbare Alternative vor.

Für eine umfangreichere Funktionalität könnten Sie Versuchen Sie attrs Paket . Voir ein Verwendungsbeispiel . pydantic könnte auch einen Blick wert sein .

61voto

Ernesto Punkte 862

Sie können ein Klassenobjekt auch direkt verwenden; dabei wird ein Namespace erstellt:

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

58voto

Dunatotatos Punkte 1536

En mock Modul ist im Grunde dafür gemacht.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X