Zum Beispiel habe ich eine Basisklasse wie folgt:
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
Aus dieser Klasse leite ich mehrere andere Klassen ab, z
class TestClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Test')
class SpecialClass(BaseClass):
def __init__(self):
super(TestClass, self).__init__('Special')
Gibt es eine schöne, pythonische Möglichkeit, diese Klassen dynamisch durch einen Funktionsaufruf zu erstellen, der die neue Klasse in meinen aktuellen Bereich einfügt, wie z.
foo(BaseClass, "My")
a = MyClass()
...
Da es Kommentare und Fragen geben wird, warum ich das brauche: Die abgeleiteten Klassen haben alle genau die gleiche interne Struktur mit dem Unterschied, dass der Konstruktor eine Reihe von zuvor undefinierten Argumenten verwendet. So nimmt zum Beispiel MyClass
die Schlüsselwörter, a
während der Konstruktor der Klasse und TestClass
nimmt .b
c
inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")
Sie sollten jedoch NIEMALS den Typ der Klasse als Eingabeargument verwenden
inst1 = BaseClass(classtype = "My", a=4)
Ich habe das zum Laufen gebracht, würde aber den anderen Weg bevorzugen, dh dynamisch erstellte Klassenobjekte.
quelle
a
, wird es immer seinMyClass
undTestClass
wird es nie nehmena
? Warum nicht einfach alle 3 Argumente deklarieren,BaseClass.__init__()
sondern standardmäßig alle aufNone
?def __init__(self, a=None, b=None, C=None)
?Antworten:
Mit diesem Code können Sie neue Klassen mit dynamischen Namen und Parameternamen erstellen. Die Parameterüberprüfung in
__init__
just erlaubt keine unbekannten Parameter. Wenn Sie andere Überprüfungen wie den Typ benötigen oder diese obligatorisch sind, fügen Sie einfach die Logik dort hinzu:Und das funktioniert zum Beispiel so:
Ich sehe, dass Sie darum bitten, die dynamischen Namen in den Namensbereich einzufügen - das wird in Python nicht als gute Vorgehensweise angesehen - Sie haben entweder Variablennamen, die zur Codierungszeit bekannt sind, oder Daten - und Namen, die zur Laufzeit gelernt wurden, sind mehr " Daten "als" Variablen "-
Sie können Ihre Klassen also einfach einem Wörterbuch hinzufügen und von dort aus verwenden:
Und wenn Ihr Design unbedingt die Namen benötigt, um in den Geltungsbereich zu gelangen, machen Sie dasselbe, aber verwenden Sie das vom
globals()
Aufruf zurückgegebene Wörterbuch anstelle eines beliebigen Wörterbuchs:(Es wäre in der Tat möglich, dass die Klassenfactory-Funktion den Namen dynamisch in den globalen Bereich des Aufrufers einfügt. Dies ist jedoch eine noch schlechtere Vorgehensweise und nicht für alle Python-Implementierungen kompatibel. Der Weg dazu besteht darin, den Namen des Aufrufers abzurufen Ausführungsrahmen über sys._getframe (1) und Festlegen des Klassennamens im globalen Wörterbuch des Rahmens in seinem
f_globals
Attribut).update, tl; dr: Diese Antwort war populär geworden, immer noch sehr spezifisch für den Fragetext. Die allgemeine Antwort zum "dynamischen Erstellen abgeleiteter Klassen aus einer Basisklasse" in Python ist ein einfacher Aufruf zum
type
Übergeben des neuen Klassennamens, ein Tupel mit den Basisklassen und dem__dict__
Hauptteil für die neue Klasse - wie folgt :Update
Jeder, der dies benötigt, sollte auch das Dill- Projekt überprüfen - es behauptet, in der Lage zu sein, Klassen zu beizen und zu entfernen, genau wie es Beizen bei normalen Objekten tut, und hat es in einigen meiner Tests gelebt.
quelle
BaseClass.__init__()
wäre es besser als die allgemeineresuper(self.__class__).__init__()
, die besser spielt, wenn die neuen Klassen in Unterklassen unterteilt sind. (Referenz: rhettinger.wordpress.com/2011/05/26/super-considered-super )super
oben zu ersetzen, und erstellen Sie eine Unterklasse einer dynamisch erstellten Klasse, um es zu verstehen. Andererseits können Sie in diesem Fall die Basisklasse als allgemeines Objekt verwenden, von dem aus Sie aufrufen können__init__
.__init__
aus,BaseClass
als würde von mit einem Argument aufgerufen, aber tatsächlich wirdBaseClass.__init__
immer eine beliebige Liste von Schlüsselwortargumenten verwendet. Zweitens legt die obige Lösung alle zulässigen Parameternamen als Attribute fest, was ich nicht möchte. JEDES Argument muss verwendet werdenBaseClass
, aber welches kenne ich beim Erstellen der abgeleiteten Klasse? Ich werde die Frage wahrscheinlich aktualisieren oder eine genauere Frage stellen, um sie klarer zu machen.super()
ich erwähnte, gibtTypeError: must be type, not SubSubClass
. Wenn ich das richtig verstehe, kommt dies aus dem ersten Argumentself
von__init__()
,SubSubClass
bei dem eintype
Objekt erwartet wird: Dies scheint damit verbunden zu sein, dasssuper(self.__class__)
es sich um ein ungebundenes Superobjekt handelt. Was ist ihre__init__()
Methode? Ich bin mir nicht sicher, für welche Methode ein erstes Argument vom Typ erforderlich sein könntetype
. Könntest du erklären? (Randnotiz: Meinsuper()
Ansatz macht hier in der Tat keinen Sinn, weil er__init__()
eine variable Signatur hat.)type()
ist die Funktion, die Klassen (und insbesondere Unterklassen) erstellt:quelle
TypeError
solches erhalten__init__() takes exactly 2 arguments (1 given)
. Ich fand, dass das Hinzufügen von etwas (irgendetwas?), Um die Lücke zu füllen, ausreichen würde. Läuft beispielsweiseobj = SubClass('foo')
fehlerfrei.SubClass
es sich um eine Unterklasse vonBaseClass
in der Frage handelt undBaseClass
ein Parameter verwendet wird (classtype
wie'foo'
in Ihrem Beispiel).Überprüfen Sie den folgenden Code, um eine Klasse mit einem dynamischen Attributwert zu erstellen. NB. Dies sind Codefragmente in der Programmiersprache Python
quelle