Цей біт коду дозволяє створювати нові класи з динамічними іменами та іменами параметрів. Перевірка параметрів __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(...)
(Дійсно, функція заводу класу могла б динамічно вставляти ім'я в глобальну область дії абонента, - але це ще гірша практика, і вона не сумісна в реалізаціях Python. Спосіб зробити це - отримати виконання кадру через sys._getframe (1) та встановлення імені класу в глобальному словнику кадру в його f_globalsатрибуті).
update, tl; dr: Ця відповідь стала популярною, все ще дуже специфічною для питання. Загальною відповіддю про те, як
"динамічно створювати похідні класи з базового класу"
у Python, є простий виклик typeпередачі нового імені класу, кортежу з базовим класом (класами) та __dict__тілом для нового класу, як це:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
оновити
Будь-хто, хто потребує цього, також повинен перевірити проект кропу - він стверджує, що може маринувати та розпаковувати класи так само, як це робить маринований звичайні предмети, і дожив до цього в деяких моїх тестах.
aце завжди будеMyClassіTestClassніколи не приймеa? Чому б просто не оголосити всі 3 аргументи,BaseClass.__init__()а за замовчуванням їх усіNone?def __init__(self, a=None, b=None, C=None)?