Есть ли способ создавать подклассы на лету? - PullRequest
6 голосов
/ 14 февраля 2012

Я создаю игру, в которой у меня есть несколько сложный метод создания сущностей.

Когда уровень загружен, код загрузки читает набор файлов YAML, которые содержат атрибуты всех возможных вариантов.единицы.Используя файл YAML, он создает так называемый объект EntityResource.Этот объект EntityResource служит официальным источником информации при создании новых модулей.Цель двоякая:

  1. Обнаружение мошенничества с помощью проверки хеша на выходе файла YAML
  2. Помощь в отладке, когда вся информация о единицах поступает из одного авторитетного источника.

Эти EntityResource объекты затем подаются в EntityFactory объект для создания единиц определенного типа.

Мой вопрос заключается в следующем. есть способ динамически создавать подклассы EntityResource на основе содержимого файла YAML, читаемого в?

Кроме того, я хотел бы, чтобы каждому из этих подклассов, производных от файла YAML, был присвоен метакласс одиночного,Любые предостережения?

Ответы [ 3 ]

24 голосов
/ 14 февраля 2012

Я не уверен, что это то, что вы ищете, но вы можете использовать type для динамического создания подклассов:

SubClass = type('SubClass', (EntityResource,), {})

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

class SubClass(EntityResource):
    A=1
    B=2

, то это будет переведено в:

 SubClass = type('SubClass', (EntityResource,), {'A': 1, 'B': 2})

где:

  • ПервыйАргумент - это просто имя класса
  • Второй аргумент - это список родительских классов
  • Третий аргумент - это словарь, инициализирующий объект класса.Это включает не только атрибуты класса, но и методы.
4 голосов
/ 14 февраля 2012

Можно создавать подклассы на лету. Это не значит, что ты должен. В любом случае я предоставлю механизм.

Атрибут base в каждом классе указывает цепочку наследования:

class Animal(object):
    pass

class Dog(Animal):
    pass

print Animal.__bases__
print Dog.__bases__
# prints:
#(<type 'object'>,)
#(<class '__main__.Animal'>,)

Итак, __bases__ - это кортеж с «основами наследования». Вы можете заменить этот кортеж (вы не можете «добавлять к нему» или «извлекать из него», потому что это кортеж, а кортежи неизменны). Например, скажем, что у вас есть «класс mixin», который добавляет функциональность некоторым подклассам животных, но не другим:

class Animal(object):
    pass

class Dog(Animal):
    pass

class Cat(Animal):
    pass

class TalkMixin(object):
    def talk(self):
        print("I talk like a {0}".format(self.__class__.__name__))

if __name__ == "__main__":

    dog = Dog()
    cat = Cat()

    try:
        dog.talk() 
        cat.talk()
    except AttributeError:
        print("Great - the program raised AttributeError, as expected")

    # now, add the MixIn to the class "Dog", but not to the class
    # "Cat" - do this on the fly:
    old_dog_bases = Dog.__bases__
    Dog.__bases__ = (Animal, TalkMixin)

    # this should be successful!
    dog.talk()

    try:
        cat.talk()
    except AttributeError:
        print("As expected, cat.talk() raised AttributeError")

    # now do the same (add the mixin dynamically - via inheritance) to
    # the Cat
    old_cat_bases = Cat.__bases__
    Cat.__bases__ = (Animal, TalkMixin)

    # this should be successful!
    cat.talk()

    # Now, remove the mixin (drop from the inheritance) for both cats
    # and dogs:
    Dog.__bases__ = old_dog_bases
    Cat.__bases__ = old_cat_bases

    try:
        dog.talk()
        cat.talk()
    except AttributeError:
        print("as expected, they can no longer talk")

Создает следующий вывод:

Great - the program raised AttributeError, as expected
I talk like a Dog
As expected, cat.talk() raised AttributeError
I talk like a Cat
as expected, they can no longer talk

Многие люди считают классы MixIn злыми. И они могут быть правы! Вы можете себе представить, что если вы испортили атрибут base , вы в значительной степени разрушили вашу программу. Итак, это так - вы можете динамически изменять наследование объекта, но это не значит, что вы должны (вероятно, абстрактные классы или реализация концепции?)

1 голос
/ 14 февраля 2012

Когда я слышу «создание подклассов на лету», я понимаю «создание объектов, которые ведут себя по-разному на лету», что на самом деле является вопросом конфигурации .

Есть ли что-то, что вынужно, что вы не можете получить, просто читая некоторые данные и создавая объект, который решает, как он будет себя вести, основываясь на том, что он читает?

Вот метафора: я удобный парень - ямогу собрать любой предмет ИКЕА, который ты мне бросишь.Но каждый раз я не другой человек, я просто один и тот же удобный парень, который читает разные схемы и ищет разные виды шурупов и кусков дерева.Это мое объяснение, что подклассы не являются натуральными решениями здесь.

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