有没有办法在运行中创建子类?

时间:2012-02-13 23:59:04

标签: python class singleton subclass subclassing

我正在创建一个游戏,其中我有一个复杂的创建实体的方法。

加载关卡时,加载代码会读取一堆YAML文件,这些文件包含所有不同可能单元的属性。使用YAML文件,它会创建一个所谓的EntityResource对象。此EntityResource对象在生成新单元时充当信息的权威来源。目标是双重的:

  1. 通过对YAML文件的输出实施哈希检查来确定作弊行为
  2. 通过让所有单位信息来自单一的权威来源来帮助调试。
  3. 然后将这些EntityResource对象输入EntityFactory对象以生成特定类型的单位。

    我的问题如下。有没有办法根据正在读取的YAML文件的内容动态创建EntityResource的子图块?

    另外,我希望为这些YAML文件派生的每个子类分配一个单独的元类。有什么警告吗?

3 个答案:

答案 0 :(得分:24)

我不确定这是否是您正在寻找的,但您可以使用type动态创建子类:

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

修改:要了解type的工作原理,您只需要翻译如何编写课程并将其转换为type调用。例如,如果你想写类似的东西:

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

然后,那将被翻译为:

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

其中:

  • 第一个参数只是类名
  • 第二个参数是父类列表
  • 第三个参数是字典初始化类对象。这不仅包括类属性,还包括方法。

答案 1 :(得分:4)

可以动态创建子类。这并不意味着你应该这样做。无论如何,我会提供一种机制。

每个类中的 bases 属性告诉您继承链:

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 属性,你几乎毁掉了你的程序。那么,它就是 - 你可以动态地改变一个对象的继承,但这并不意味着你应该(可能是抽象类或概念实现?)

答案 2 :(得分:1)

当我听到“动态创建子类”时,我理解“创建在运行中表现不同的对象”,这实际上是配置的问题。

您是否需要通过读取某些数据并根据其读取的内容创建一个决定其行为方式的对象来获取所需的内容?

这是比喻:我是一个方便的人 - 我可以把你扔给我的任何宜家物品放在一起。但我每次都不是一个与众不同的人,我只是在阅读不同的图表并寻找不同种类的螺丝和木头的同样方便的人。这就是我在这里将子类化不是自然解决方案的原因。