2010-05-28 77 views
1

我有代碼,靜態寄存器(type, handler_function)對在模塊加載時,導致這樣一個字典:排序對象的類型

HANDLERS = { 
    str: HandleStr, 
    int: HandleInt, 
    ParentClass: HandleCustomParent, 
    ChildClass: HandleCustomChild 
    } 

def HandleObject(obj): 
    for data_type in sorted(HANDLERS.keys(), ???): 
    if isinstance(obj, data_type): 
     HANDLERS[data_type](obj) 

在哪裏從ParentClassChildClass繼承。問題是,自從它是一個字典,訂單沒有被定義 - 但是如何反思類型對象以找出排序鍵

生成的順序應該是超級類(最具體類型)的子類。例如。 str出現在basestring之前,而ChildClass出現在ParentClass之前。如果類型不相關,它們之間的相對位置並不重要。

回答

4

如果你知道你總是應對新樣式類:

def numberofancestors(klass): 
    return len(klass.mro()) 

,或者,如果你擔心有可能是舊的樣式類的組合:

import inspect 

def numberofancestors(klass): 
    return len(inspect.getmro(klass)) 

,然後在這兩種情況下,

sorted(HANDLERS, key=numberofancestors, reversed=True) 

會給你你需要什麼(你不需要.keys()部分)。

@伊格納西奧的拓撲排序的建議在理論上是正確的,但因爲給定一個類,你可以很容易和快速地得到它的前體的數量(AKA「祖先」... ...在一個奇怪的意義上,是你的祖先之一;-),通過這些函數,我的方法更加實用:它依賴於一個明顯的事實,即任何派生類至少比其任何基類都多一個「祖先」,因此,與此key=,它總是會在其任何基地之前排序。

無關的類可能以任意順序結束(就像它們可能在拓撲排序中一樣),但是你已經明確表達了你並不在意這一點。

編輯:在OP,在下面的評論話題有關的多重繼承的情況下提供最佳支持沉思,想出了比「預排序」嵌入問題的最初一個完全不同的想法,但他的建議關於如何實現大幅度的想法是不是最佳:

的想法是好的(如多重繼承的支持是任何利息),但最好的實現其很可能是(Python的2.6或更高版本):

next(Handlers[c] for c in type(obj).mro() if c in Handlers) 

通常情況下,adict.get(k) and check for not Noneif k in adict: adict[k]快,但這不是一個特別正常的情況,因爲使用get需要在其上建立一個「假」單項清單和「循環」來模擬分配。

更一般地,通過建立一個理解整個名單只是爲了利用其[0]個項是多餘的工作 - 叫上genexp更像一個first,如next內置函數,「給我的第一項genexp「,除此之外沒有額外的工作。如果listcomp/genexp爲空,它將引發StopIteration而不是IndexError,但這通常不是問題;如果genexp爲空,您也可以使用next的第二個參數作爲「默認值」。

在2.5和更早的版本中,您必須改用(thegenexp).next()(而且沒有辦法給它一個默認參數),但是在語法上稍微有些閃亮,它或多或少等價於2.6更好的構造語義和速度。

我確信很高興繼續討論評論,因爲我認爲這個結論是有價值的並且可能有用(儘管可能不在OP的應用程序的確切環境中,其中多重繼承實際上可能不是問題) 。

+0

非常聰明!這對於多繼承的情況並不適用,但我不打算處理這種用例。 – 2010-05-28 18:09:54

+0

@Richard,你能告訴我一個多重繼承失敗的案例嗎?我想我已經證明沒有失敗的情況(多重或不是,派生類將永遠*至少有一個祖先 - 本身!),我想知道我的邏輯在哪裏使我失敗(或「我失敗了我的邏輯「;-) - 但我的腦袋因爲我無法想象_任何失敗的案例而受挫(當然,因爲繼承圖總是DAG)......它似乎抵消了大部分圖論的基本基礎。所以在此先感謝提供反例! – 2010-05-28 21:01:34

+0

我沒有想太深,但是我想到的是這樣的: << class A; [A] ncestors = 1 // B類(A); a = 2 // class One; a = 1 // class Two(One); a = 2 // class Alice(B,One); a = 3 // class Bob(A,Two); a和3 // 寄存器(A,HandleA)// 寄存器(One,HandleOne)>> A和One具有相同的排序順序,因此它們的位置相對於彼此是未定義的。當我們去匹配Alice()或Bob()的實例時,我們將隨機獲得HandleA或HandleOne(因爲它們都是A和One的子類型)。無可否認,我很難想到這種情況何時會發生。 – 2010-05-29 02:32:54

0

使用Python 2.7或3.1中的collections.OrderedDict。它是用純Python編寫的,所以如果需要,你可以很容易地將它插入或適應早期版本。

An OrderedDict將保持插入順序。