it-swarm.com.de

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

Ich möchte ein dynamisches Objekt (in einem anderen Objekt) in Python erstellen und 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?

edit:

Ich setze die Attribute aus einer for-Schleife, die eine Liste von Werten durchläuft, z.

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

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

Im obigen Beispiel würde ich obj.a.attr1, obj.a.attr2, obj.a.attr3 erhalten. 

Ich habe die setattr-Funktion verwendet, weil ich nicht wusste, wie obj.a.NAME von einer for-Schleife ausgeführt werden soll.

Wie würde ich das Attribut basierend auf dem Wert von p im obigen Beispiel festlegen?

238
John

Sie könnten mein uraltes Bunch - Rezept verwenden, aber wenn Sie keine "Bündelklasse" erstellen möchten, gibt es bereits eine sehr einfache in Python - alle Funktionen können beliebige Attribute (einschließlich Lambda-Funktionen) haben. Also die folgenden Arbeiten:

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

Ob der Verlust an Klarheit im Vergleich zum ehrwürdigen Bunch-Rezept in Ordnung ist, ist eine Stilentscheidung, die ich Ihnen natürlich überlassen werde.

176
Alex Martelli

Die integrierte Variable object kann instanziiert werden, es dürfen jedoch keine Attribute gesetzt sein. (Ich wünschte, es könnte zu genau diesem Zweck.) Es hat keinen __dict__ für die Attribute.

Ich mache das im Allgemeinen einfach:

class Object(object):
    pass

a = Object()
a.somefield = somevalue

Wenn ich kann, gebe ich der Object-Klasse einen aussagekräftigeren Namen, je nachdem, welche Art von Daten ich in sie stecke.

Einige Leute machen eine andere Sache, wenn sie eine Unterklasse von dict verwenden, die den Zugriff auf Attribute an den Schlüsseln erlaubt. (d.key statt d['key'])

Edit : Für den Zusatz zu Ihrer Frage ist die Verwendung von setattr in Ordnung. Sie können setattr nicht für object()-Instanzen verwenden.

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

Es gibt eine 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änderliche Alternative vor.

Für eine umfangreichere Funktionalität können Sie versuchen, attrs package . Siehe ein Beispiel zur Verwendung .

95
jfs

Es gibt mehrere Möglichkeiten, um dieses Ziel zu erreichen ... Grundsätzlich brauchen Sie ein Objekt, das erweiterbar ist.

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

obj.b = lambda:None

class Test:
  pass
obj.c = Test()
30
evilpie

Jetzt können Sie tun (nicht sicher, ob es die gleiche Antwort wie böse ist):

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

Das mock-Modul ist grundsätzlich dafür gemacht.

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

Probieren Sie den folgenden Code aus:

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

wie Dokumente sagen :

Note: object hat nicht einen __dict__, so dass Sie einer Instanz der object-Klasse keine beliebigen Attribute zuordnen können.

Sie können einfach eine Dummy-Klasseninstanz verwenden.

7
SilentGhost

Sie können ein Klassenobjekt auch direkt verwenden. Es wird ein Namespace erstellt:

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

Diese Lösungen sind beim Testen sehr hilfreich. Aufbauend auf den Antworten aller anderen, mache ich das in Python 2.7.9 (ohne statische Methode bekomme ich einen TypeError (ungebundene Methode ...):

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

Wenn wir vor dem Erstellen des verschachtelten Objekts alle Attribute und Werte ermitteln und zusammenfassen können, können Sie eine neue Klasse erstellen, die beim Erstellen ein Wörterbuchargument verwendet.

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

Wir können auch Schlüsselwortargumente zulassen. Siehe diesen Beitrag

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')
0
HarlemSquirrel

Spät am Tag kommen wir hierher, aber hier ist mein Pennyworth mit einem Objekt, das zufällig einige nützliche Pfade in einer App enthält, aber Sie können es für alles anpassen, wo Sie ein Dict von Informationen wünschen, auf die Sie mit getattr und dot Notation zugreifen können (Was ich glaube, um diese Frage geht es wirklich):

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

Das ist cool, weil jetzt:

In [1]: x_path.projects
Out[1]: '/home/x/projects'

In [2]: x_path('caches')
Out[2]: '/home/x/caches'

Das verwendet also das Funktionsobjekt wie die obigen Antworten, verwendet jedoch die Funktion, um die Werte abzurufen (Sie können auch (getattr, x_path, 'repository') anstelle von x_path('repository') verwenden, wenn Sie dies vorziehen).

0
Paul Whipp

Welche Objekte verwenden Sie? Ich habe es gerade mit einer Musterklasse ausprobiert und es hat gut funktioniert:

class MyClass:
  i = 123456
  def f(self):
    return "hello world"

b = MyClass()
b.c = MyClass()
setattr(b.c, 'test', 123)
b.c.test

Und ich bekam 123 als Antwort.

Die einzige Situation, in der ich dies als fehlerhaft sehe, ist, wenn Sie eine setattr an einem eingebauten Objekt versuchen.

Update: Aus dem Kommentar ist dies eine Wiederholung von: Warum können Sie einem Objekt in Python keine Attribute hinzufügen?

0
jneves