2010-07-20 14 views
15

Ich habe eine Python-Klasse mit Attributen mit den Namen: date1, date2, date3 usw.Wie können Klassenattribute in Python dynamisch erstellt und aufgerufen werden?

Während der Laufzeit habe ich eine Variable i, die eine ganze Zahl ist.

Was ich tun möchte, ist auf das entsprechende Datum Attribut in der Laufzeit basierend auf dem Wert von i zuzugreifen.

Zum Beispiel

wenn i == 1, möchte ich myobject.date1

zugreifen, wenn i == 2, I myobject.date2

zugreifen möchten Und ich tun möchte, etwas ähnliches für Klasse statt Attribut.

Zum Beispiel habe ich eine Reihe von Klassen: MyClass1, MyClass2, MyClass3, etc. Und ich habe eine Variable k.

wenn k == 1, ich will

wenn k == 2, eine neue Instanz von MyClass1 instanziiert ich kann ich das tun, um eine neue Instanz von MyClass2

Wie instanziiert will?

EDIT

Ich hoffe, mit einem Riesen zu vermeiden if-then-else-Anweisung der entsprechenden Attribut/Klasse auszuwählen.

Gibt es in Python eine Möglichkeit, den Klassennamen spontan mit dem Wert einer Variablen zu erstellen?

+2

bearbeiten Sie bitte diese Frage. Bitte lesen Sie die Formatierungshinweise auf der rechten Seite der Seite. Bitte formatieren Sie Ihren Code richtig. –

+1

Bitte formatieren Sie diese Frage korrekt. Ich möchte es als eine nützliche Frage aufwerten, da dies ein sehr schönes Beispiel für Metaprogrammierung und Introspektion ist. Aber es muss bearbeitet werden. –

Antwort

19

Sie getattr() verwenden können, eine Eigenschaft zuzugreifen, wenn Sie dies nicht tun kenne seinen Namen erst zur Laufzeit:

obj = myobject() 
i = 7 
date7 = getattr(obj, 'date%d' % i) # same as obj.date7 

Wenn Sie Ihre nummerierten Klassen in einem Modul zu halten genannt foo, Sie getattr() wieder verwenden können, auf sie zuzugreifen durch Nummer.

foo.py: 
    class Class1: pass 
    class Class2: pass 
    [ etc ] 


bar.py: 
    import foo 
    i = 3 
    someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3 
    obj = someClass() # someClass is a pointer to foo.Class3 
    # short version: 
    obj = getattr(foo, "Class%d" % i)() 

Nachdem alles gesagt, dass Sie wirklich diese Art der Sache vermeiden sollte, weil Sie nie durch das Lesen durch Ihre gesamte Code-Basis, außer diese nummerierten Objekte und Klassen verwendet, um herauszufinden, wo der Lage sein werden. Du solltest besser alles in ein Wörterbuch schreiben.

+4

Muss diesen letzten Absatz mit einem großen, roten Marker betonen. Es gibt 2+ Kennungen mit dem gleichen Namen und eine laufende Nummer am Ende? Refactor es. Das heißt, es sei denn, Sie haben einen Grund, der doppelt so gut ist, wie nötig, um als guter Grund angesehen zu werden. – delnan

+0

Völlig einverstanden. Angesichts einer Auswahl würde ich Code wie diesen niemals passieren lassen. – Daenyth

0

Für das erste Beispiel würde ich eine Instanzmethode für die Klasse hinzufügen.

def get_date_for_i(self, i): 
    if i == 1: 
     return self.date1 
    elif i == 2: 
     return self.date2 
    # etc... 

Für die zweite ich eine Fabrik-Funktion verwenden würden:

def get_class_for_k(k): 
    if k == 1: 
     return MyClass1 
    if k == 2: 
     return MyClass2 

    # etc... 
+0

Nun, ich versuche, eine riesige Wenn-dann-sonst-Aussage zu vermeiden. – Continuation

4

OK, gut ... Es scheint, wie dies ein wenig Arbeit braucht. Erstens sollten sie für Ihre Date-Dinge vielleicht als ein Attribut-Diktat gespeichert werden. zB myobj.dates[1], so weiter.

Für die Klassen klingt es nach Polymorphie. Alle Ihre MyClass * -Klassen sollten einen gemeinsamen Vorfahren haben. Die Methode __new__ des Vorfahren sollte herausfinden, welche seiner Kinder instanziiert werden.

Ein Weg für die Eltern zu wissen, was zu machen ist, ein Diktat der Kinder zu halten. Es gibt Möglichkeiten, dass die Elternklasse ihre untergeordneten Elemente nicht auflisten muss, indem sie nach allen Unterklassen sucht, aber es ist etwas komplexer zu implementieren. Weitere Informationen dazu, wie Sie diesen Ansatz verwenden könnten, finden Sie unter here. Lesen Sie die Kommentare vor allem, sie erweitern es.

class Parent(object): 
    _children = { 
     1: MyClass1, 
     2: MyClass2, 
    } 

    def __new__(k): 
     return object.__new__(Parent._children[k]) 

class MyClass1(Parent): 
    def __init__(self): 
     self.foo = 1 

class MyClass2(Parent): 
    def __init__(self): 
     self.foo = 2 

bar = Parent(1) 
print bar.foo # 1 
baz = Parent(2) 
print bar.foo # 2 

Drittens sollten Sie wirklich Ihre variable Benennung überdenken. Verwenden Sie keine Zahlen, um Ihre Variablen aufzuzählen, sondern geben Sie ihnen aussagekräftige Namen. i und k sind schlecht zu verwenden, da sie konventionell für Schleifenindizes reserviert sind.

Ein Beispiel Ihres vorhandenen Codes wäre sehr hilfreich bei der Verbesserung.

+0

Wie würde die __new__ Methode des Vorfahren herausfinden, welche Kinder instanziiert werden, ohne auf eine große if-then-else-Anweisung zurückzugreifen? Ich hoffe, den Variablenwert zu verwenden, um den Klassennamen direkt "zu verfassen". Ist das in Python möglich? – Continuation

+0

@Continuation: Ich habe meine Antwort aktualisiert, um weitere Informationen zu enthalten – Daenyth

+0

Ich habe den Fall, dass die Attribute NameInfo, GroupInfo usw. stammt aus vSphere API, und was auf diese dynamisch/programmatisch in einer iterativen Schleife zugreifen, dann das Wörterbuch nicht t ziemlich Arbeit für mich – Hvisage

5

Für den ersten Fall, sollten Sie tun können:

getattr(myobject, 'date%s' % i) 

Für den zweiten Fall können Sie tun:

myobject = locals()['MyClass%s' % k]() 

jedoch die Tatsache, dass Sie dies tun müssen, um in Der erste Punkt kann ein Zeichen dafür sein, dass Sie sich dem Problem auf sehr nicht-pythonische Weise nähern.

2

Ich stimme mit Daenyth, aber wenn Sie frech sich fühlen, können Sie die dict Methode verwenden, die mit allen Klassen kommt:

>>> class nullclass(object): 
     def nullmethod(): 
      pass 

>>> nullclass.__dict__.keys() 
['__dict__', '__module__', '__weakref__', 'nullmethod', '__doc__'] 

>>> nullclass.__dict__["nullmethod"] 
<function nullmethod at 0x013366A8> 
1

eine Liste aller Attribute zu erhalten, versuchen:

dir(<class instance>) 
Verwandte Themen