Python: фабрика классов, использующая пользовательский ввод в качестве имен классов - PullRequest
11 голосов
/ 17 марта 2010

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

Существует суперкласс "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")  

но не повезло. Думаю, я не совсем понял, что здесь делает new В результате я хочу получить

class Soldier(Unit):
    pass

создается фабрикой. И если я назову фабрику с аргументом «Рыцарь», я бы хотел, чтобы был создан класс Рыцарь, подкласс Unit.

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

Ответы [ 2 ]

14 голосов
/ 17 марта 2010

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

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

    cls.__name__ = name
    return cls

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

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

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

Имя класса - первый аргумент для типа - присваивается __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())

7 голосов
/ 17 марта 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...