Подтвердить что ты не робот

Как я могу динамически создавать производные классы из базового класса

Например, у меня есть базовый класс следующим образом:

class BaseClass(object):
    def __init__(self, classtype):
        self._type = classtype

Из этого класса я получаю несколько других классов, например

class TestClass(BaseClass):
    def __init__(self):
        super(TestClass, self).__init__('Test')

class SpecialClass(BaseClass):
    def __init__(self):
        super(TestClass, self).__init__('Special')

Есть ли хороший, путинский способ динамического создания этих классов с помощью вызова функции, который помещает новый класс в мою текущую область, например:

foo(BaseClass, "My")
a = MyClass()
...

Так как будут комментарии и вопросы, почему мне это нужно: производные классы имеют ту же внутреннюю структуру с разницей, что конструктор принимает несколько ранее аргументов undefined. Так, например, MyClass принимает ключевые слова a, а конструктор класса TestClass принимает b и c.

inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")

Но они НИКОГДА не должны использовать тип класса в качестве входного аргумента, например

inst1 = BaseClass(classtype = "My", a=4)

Я получил это для работы, но предпочел бы другой способ, то есть динамически созданный объект класса.

4b9b3361

Ответ 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 - он утверждает, что способен рассолковывать и разбрасывать классы, как и маринование, на обычные объекты и дожили до этого в некоторых моих тестах.

Ответ 2

type() - это функция, которая создает классы (и, в частности, подклассы):

def set_x(self, value):
    self.x = value

SubClass = type('SubClass', (BaseClass,), {'set_x': set_x})
# (More methods can be put in SubClass, including __init__().)

obj = SubClass()
obj.set_x(42)
print obj.x  # Prints 42
print isinstance(obj, BaseClass)  # True

Ответ 3

Чтобы создать класс со значением динамического атрибута, оформите код ниже. NB. Это фрагменты кода на языке программирования Python

def create_class(attribute_data, **more_data): # define a function with required attributes
    class ClassCreated(optional extensions): # define class with optional inheritance
          attribute1 = adattribute_data # set class attributes with function parameter
          attribute2 = more_data.get("attribute2")

    return ClassCreated # return the created class

# use class

myclass1 = create_class("hello") # *generates a class*