Ответ 1
Этот бит кода позволяет создавать новые классы с динамическими
имена и имена параметров.
Проверка параметров в __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():
# 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
И это работает так, например:
>>> 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(...)
(действительно, функция класса factory могла бы динамически вставлять имя в глобальную область вызывающего объекта, но это еще хуже, и не совместимо с реализацией Python. чтобы получить кадр выполнения звонящего, sys._getframe (1) и установить имя класса в глобальном словаре фрейма в его атрибуте f_globals
).
update, tl; dr: Этот ответ стал популярным, но тем не менее его очень специфичным для органа вопроса. Общий ответ о том, как
"динамически создавать производные классы из базового класса"
в Python - это простой вызов type
передачи нового имени класса, кортежа с базовым классом (es) и тегом __dict__
для нового класса - например:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
Обновление
Любой, кто нуждается в этом, также должен проверить проект dill - он утверждает, что способен рассолковывать и разбрасывать классы, как и маринование, на обычные объекты и дожили до этого в некоторых моих тестах.