2012-02-13 107 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 

很多人認爲混入類惡。他們可能是對的!你可以想象,如果你搞砸基地屬性,你幾乎摧毀了你的程序。所以,它是 - 你可以動態地改變一個對象的繼承,但這並不意味着你應該(可能抽象類或概念實現?)

相關問題