Questo bit di codice consente di creare nuove classi con nomi dinamici e nomi di parametri. La verifica dei parametri in __init__
appena non consente parametri sconosciuti, se hai bisogno di altre verifiche, come il tipo, o che sono obbligatorie, aggiungi la logica lì:
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
E funziona così, ad esempio:
>>> 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
Vedo che stai chiedendo di inserire i nomi dinamici nell'ambito dei nomi - ora, questa non è considerata una buona pratica in Python - o hai nomi di variabili, noti al momento della codifica, o dati - e i nomi appresi in runtime sono più " dati "rispetto a" variabili "-
Quindi, potresti semplicemente aggiungere le tue classi a un dizionario e usarle da lì:
name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)
E se il tuo progetto ha assolutamente bisogno che i nomi rientrino nell'ambito, fai lo stesso, ma usa il dizionario restituito dalla globals()
chiamata invece di un dizionario arbitrario:
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(Sarebbe davvero possibile per la funzione class factory inserire il nome dinamicamente nell'ambito globale del chiamante, ma questa è una pratica ancora peggiore e non è compatibile con le implementazioni Python. Il modo per farlo sarebbe ottenere il frame di esecuzione, tramite sys._getframe (1) e impostando il nome della classe nel dizionario globale del frame nel suo f_globals
attributo).
update, tl; dr: questa risposta è diventata popolare, ma è ancora molto specifica per il corpo della domanda. La risposta generale su come
"creare dinamicamente classi derivate da una classe base"
in Python è una semplice chiamata per type
passare il nome della nuova classe, una tupla con le classi base e il __dict__
corpo per la nuova classe, come questo:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
update
Chiunque abbia bisogno di questo dovrebbe anche controllare il progetto Dill - afferma di essere in grado di mettere in saccoccia e dissotterrare le classi proprio come fa Pickle con gli oggetti ordinari, e ci ha vissuto in alcuni dei miei test.
a
sarà sempreMyClass
eTestClass
non lo prenderò maia
? Perché non solo dichiarare tutti e 3 gli argomentiBaseClass.__init__()
ma impostarli come predefinitiNone
?def __init__(self, a=None, b=None, C=None)
?