2012-02-13 84 views
4

我正在创建一个游戏,其中有一些创建实体的复杂方法。有没有办法在运行中创建子类?

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

  1. 由具有来自单一,权威来源的所有单位信息实现在调试YAML文件
  2. 援助的输出哈希检查制止作弊。

这些对象然后被送入EntityFactory对象以生成特定类型的单元。

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

此外,我希望每个这些YAML文件派生的子类被分配一个单身元类。任何警告?

+0

你有没有复习这个问题http://stackoverflow.com/questions/ 3915024 /动态创建类-python? – amirouche 2012-02-14 00:05:31

+0

你是什么意思的单身元类? – amirouche 2012-02-14 00:05:45

+0

@abki我没有。现在正在阅读... – blz 2012-02-14 00:13:02

回答

21

我不知道如果这是你在找什么,但你可以使用type动态创建子类:

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

编辑:要了解如何type的作品,你只需要翻译如何你会写课程并将其翻译成type调用。例如,如果你想写类似:

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

话,那将被转换为:

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

其中:

  • 第一个参数就是类名
  • 第二个参数是父类的列表
  • 第三个参数是di ctionary初始化类对象。这不仅包括类属性,还包括方法。
+0

这似乎是我需要的。你会碰巧有一个更完整的例子吗?我发现Python文档有点混乱... – blz 2012-02-14 00:16:47

+0

@blz我已经添加了更详细的解释。我希望这有帮助。 – jcollado 2012-02-14 00:22:28

+0

我试过这个,我得到一个'TypeError:一个新风格的类不能只有经典的基础'。向父类元组添加'object'似乎解决了这个问题。这看起来像是正确的解决方案吗? – blz 2012-02-14 10:33:08

1

当我听到“即时创建子类”时,我明白“创建对象的行为不同”,这实际上是配置的问题。

有没有什么您需要的东西,只需读取一些数据并创建一个对象,根据它读取的内容决定它的行为方式就无法获得它?

这里是比喻:我是一个方便的家伙 - 我可以放在一起,你扔在我身上的任何宜家物品。但我每次都不是一个不同的人,我只是一个阅读不同的图表并且寻找不同种类的螺丝钉和木头的方便的人。这是我的推理不是在这里的天然解决方案。

+0

我需要的东西不能通过创建具有不同值的对象来完成,因此将对象设置为单例。我希望每个单元类型都有一个* EntityResource'实例。 – blz 2012-02-14 00:15:57

+1

这也可以解决。您已经需要跟踪哪些子类已经创建,以便您不重新创建它们,对吗?可以创建对象,保留由单元类型引用的对象表,并在创建时确保对象不是现有配置的副本,而不是创建类并使每个类成为单例。 – leoger 2012-02-14 01:10:19

+0

使用单例的想法是我*不需要跟踪哪些类已经创建。我可以迭代一个目录的内容并开始构建对象。解决方案的问题是它需要代码来明确检查重复项。这是一个* posteriori *检查,而不是*先验*禁止。当你确实需要一个类的单个实例时,任何东西都不能代替单例。 – blz 2012-02-14 12:33:57

2

可以在运行中创建子类。这并不意味着你应该。无论如何,我会提供一个机制。

基地每班属性告诉你的继承链:

class Animal(object): 
    pass 

class Dog(Animal): 
    pass 

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

所以,__bases__与“传承基地”的元组。你可以替换这个元组(你不能“追加到它”或“从它弹出”,因为它是一个元组,而元组是不可变的)。例如,假设你有一个“混合类”,这增加了功能的一些动物的子类而不是其他:

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 

很多人认为混入类恶。他们可能是对的!你可以想象,如果你搞砸基地属性,你几乎摧毁了你的程序。所以,它是 - 你可以动态地改变一个对象的继承,但这并不意味着你应该(可能抽象类或概念实现?)

相关问题