Этот фрагмент кода позволяет вам создавать новые классы с динамическими именами и именами параметров. Проверка параметров __init__
просто не позволяет использовать неизвестные параметры, если вам нужны другие проверки, например тип, или что они являются обязательными, просто добавьте туда логику:
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():
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
А работает это, например, так:
>>> 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
Я вижу , вы просите для вставки имен динамических в рамках именования - теперь, что не считается хорошей практикой в Python - вы либо имена переменных, известные во время кодирования или данные - и имена выучили во время выполнения более " данные "чем" переменные "-
Итак, вы можете просто добавить свои классы в словарь и использовать их оттуда:
name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)
И если вашему дизайну абсолютно необходимо, чтобы имена входили в область видимости, просто сделайте то же самое, но используйте словарь, возвращаемый globals()
вызовом, вместо произвольного словаря:
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(Действительно, функция фабрики классов могла бы динамически вставлять имя в глобальную область действия вызывающего, но это еще худшая практика, и она несовместима с реализациями Python. Способ сделать это - получить имя вызывающей стороны фрейм выполнения через sys._getframe (1) и установив имя класса в глобальном словаре фрейма в его f_globals
атрибуте).
update, tl; dr: Этот ответ стал популярным, но все еще очень специфичен для тела вопроса. Общий ответ о том, как
«динамически создавать производные классы из базового класса»
в Python - это простой вызов для type
передачи имени нового класса, кортежа с базовым классом (-ами) и __dict__
тела нового класса, например:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
update
Любой, кто в этом нуждается, должен также проверить проект укропа - он утверждает, что может обрабатывать и очищать классы так же, как pickle делает с обычными объектами, и в некоторых из моих тестов он жил в соответствии с этим.
a
это всегда будетMyClass
иTestClass
никогда не будетa
? Почему бы просто не объявить все 3 аргумента,BaseClass.__init__()
но по умолчаниюNone
?def __init__(self, a=None, b=None, C=None)
?