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:
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
def ClassFactory(name, argnames, BaseClass=BaseClass):
def __init__(self, **kwargs):
for key, value in kwargs.items():
# here, the argnames variable is the one passed to the
# ClassFactory call
if key not in argnames:
raise TypeError("Argument %s not valid for %s"
% (key, self.__class__.__name__))
setattr(self, key, value)
BaseClass.__init__(self, name[:-len("Class")])
newclass = type(name, (BaseClass,),{"__init__": __init__})
return newclass
Und das funktioniert zum Beispiel so:
>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass
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:
name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)
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:
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(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 :
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
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.
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)
?