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

Python: класс factory с использованием ввода пользователем в качестве имен классов

Я хочу добавить класс atttributes к суперклассу динамически. Кроме того, я хочу создавать классы, которые наследуют от этого суперкласса динамически, и имя этих подклассов должно зависеть от ввода пользователем.

Существует суперкласс "Unit", к которому я могу добавлять атрибуты во время выполнения. Это уже работает.

def add_attr (cls, name, value):
    setattr(cls, name, value)

class Unit(object):
    pass

class Archer(Unit):
    pass

myArcher = Archer()
add_attr(Unit, 'strength', 5)
print "Strenght ofmyarcher: " + str(myArcher.strength)
Unit.strength = 2
print "Strenght ofmyarcher: " + str(myArcher.strength)

Это приводит к желаемому результату:
Степень могущества: 5
Степень защиты: 2

Но теперь я не хочу предопределять подкласс Archer, но я бы предпочел, чтобы пользователь решил, как назвать этот подкласс. Я пробовал что-то вроде этого:

class Meta(type, subclassname):
    def __new__(cls, subclassname, bases, dct):
    return type.__new__(cls, subclassname, Unit, dct)

factory = Meta()    
factory.__new__("Soldier")  

но не повезло. Наверное, я не совсем понял, что здесь делает новый. В результате я хочу, чтобы

class Soldier(Unit):
    pass

создается factory. И если я вызову factory с аргументом "Рыцарь", я бы хотел создать класс Knight, подкласс Unit.

Любые идеи? Большое спасибо заранее!
Bye
-Sano

4b9b3361

Ответ 1

Чтобы создать класс из имени, используйте оператор class и назначьте имя. Обратите внимание:

def meta(name):
    class cls(Unit):
        pass

    cls.__name__ = name
    return cls

Теперь, полагаю, я должен объяснить себя и так далее. Когда вы создаете класс с помощью оператора класса, он выполняется динамически - это эквивалентно вызову type().

Например, следующие два фрагмента делают одно и то же:

class X(object): pass
X = type("X", (object,), {})

Имя класса - первый аргумент type-- присваивается __name__, и что в основном его конец (единственный раз __name__ используется, вероятно, в реализации по умолчанию __repr__()). Чтобы создать класс с динамическим именем, вы можете на самом деле вызвать тип типа так, или вы можете просто изменить имя класса после этого. Синтаксис class существует по какой-то причине, хотя... он удобен, и его легко добавить и изменить позже. Если вы хотите добавить методы, например, это будет

class X(object):
    def foo(self): print "foo"

def foo(self): print "foo"
X = type("X", (object,), {'foo':foo})

и т.д. Поэтому я бы посоветовал использовать инструкцию класса - если бы вы знали, что можете сделать это с самого начала, вы, вероятно, сделали бы это. Работа с type и т.д. - это беспорядок.

(Вы не должны, между прочим, звонить type.__new__() вручную, только type())

Ответ 2

Посмотрите type() встроенную функцию.

knight_class = type('Knight', (Unit,), {})
  • Первый параметр: имя нового класса
  • Второй параметр: кортеж родительских классов
  • Третий параметр: словарь атрибутов класса.

Но в вашем случае, если подклассы не реализуют другое поведение, возможно, достаточно указать атрибут Unit a name.