2014-05-14 20 views
5

Wie würde ich eine Liste von Klassen in Python sortieren und sicherstellen, dass jede untergeordnete Klasse vor einer ihrer übergeordneten Klassen in der Liste ist?Wie kann ich eine Liste von Python-Klassen nach Vererbungstiefe sortieren?

Ich frage, weil ich sehen möchte, welcher Typ aus einer Liste von Typen, zu denen ein Objekt gehört, aber den spezifischsten Typ finden, wenn es zu mehreren gehört.

+0

Verwenden Sie 'issubclass' in Ihrer Sortierschlüsselfunktion. – njzk2

+0

(typischerweise: 'sortiert (Klassen, cmp = Lambda x, y: 1 wenn issubclass (x, y) else -1)') – njzk2

+0

@ njzk2: Dieser Komparator ist inkonsistent; Klassen ohne Vererbungsbeziehung vergleichen jeweils weniger als die andere, und eine Klasse vergleicht immer größer als sie selbst. – user2357112

Antwort

7

einfach sortieren nach len(cls.mro()).

Wenn C2 eine Unterklasse von C1 ist, muss es halten, dass len(C1.mro()) < len(C2.mro()) (weil jede Klasse in C1.mro() auch in C2.mro() erscheinen müssen). Dafür können Sie einfach sortieren nach der Länge der mro list:

class A(object): pass 
class X(object): pass 
class B(A, X): pass 
class C(B): pass 
class D(C): pass 

sorted([B, C, A, D, X], key = lambda cls: len(cls.mro())) 
=> [__main__.A, __main__.X, __main__.B, __main__.C, __main__.D] 

auch im alten Stil Klassen zu unterstützen, können Sie cls.mro() mit inspect.getmro(cls) ersetzen.

0

Ein besserer Ansatz wäre es, eine Menge zu verwenden und sich dann entlang des Vererbungsbaums der Zielklasse zu bewegen.

def find_parent(target, class_set): 
    if target in class_set: 
     return [target] 
    else: 
     bases = [] 
     for parent in target.__bases__: 
      result = find_parent(parent, class_set) 
      if result is not None: 
       bases.extend(result) 
     return bases 

Beispiel:

class A(object): 
    pass 

class B(str): 
    pass 

class C(A): 
    pass 

class D(A, dict): 
    pass 

class_set = {dict, A} 

print find_parent(A, class_set) 
print find_parent(B, class_set) 
print find_parent(C, class_set) 
print find_parent(D, class_set) 

Gibt Ihnen dieses Ergebnis:

[<class '__main__.A'>] 
[] 
[<class '__main__.A'>] 
[<class '__main__.A'>, <type 'dict'>]