按对象的类型排序

时间:2010-05-28 03:41:44

标签: python sorting

我有代码在模块加载时静态注册(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)

ChildClass继承自ParentClass的位置。问题是,由于它是一个字典,订单没有定义 - 但如何内省类型对象以找出一个排序键

结果顺序应该是子类,然后是超类(首先是大多数特定类型)。例如。 strbasestring之前,ChildClassParentClass之前。如果类型不相关,那么它们相对于彼此的位置并不重要。

3 个答案:

答案 0 :(得分:5)

如果你知道你总是在处理新式课程:

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

或者,如果您担心混合中可能存在旧式类:

import inspect

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

然后,在任何一种情况下,

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

将为您提供所需(您不需要.keys()部分)。

@ Ignacio关于拓扑排序的建议在理论上是正确的,但是因为,给定一个类,你可以轻松快速地获得它的前兆数量(AKA“祖先”......用一种奇怪的意义来说就是你的'你的祖先之一;-),使用这些numberofancestors函数,我的方法更实用:它依赖于一个明显的事实,即任何派生类至少比其任何基类都有一个“祖先”,因此,使用此key=,它将始终排在任何基础之前。

不相关的类可能以任意顺序结束(就像它们可能在拓扑类型中一样),但是你已经明确表示你不关心这个。

编辑:OP,在以下评论主题中思考多个继承案例的最佳支持,提出了一个与原始问题中嵌入的“预排序”截然不同的想法,但他关于如何实施这一极端想法的建议并非最佳:

[h for h in [HANDLERS.get(c) for c in type(obj).mro()] if h is not None][0]

这个想法很好(如果多重继承支持是有意义的),但最好的实现可能是(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上调用的next内置函数更像是first,就像在“给我genexp的第一项”一样,除了那之外没有额外的工作。如果listcomp / genexp为空,它会引发StopIteration而不是IndexError,但这通常不是问题;如果genexp为空,您还可以使用next的第二个参数作为“默认值”。

在2.5及更早版本中你必须使用(thegenexp).next()代替(并且没有办法给它一个默认参数),但在语法上有点不那么闪亮,它或多或少等同于2.6和 - 更好地构建语义和速度。

我很高兴在评论中继续讨论,因为我认为这样得出的结论是值得的并且可能有用(尽管可能不在OP的应用程序的确切环境中,其中多重继承可能实际上不是问题)。

答案 1 :(得分:1)

与每个班级的__bases__成员一起topological sort

答案 2 :(得分:0)

使用Python 2.7或3.1中的collections.OrderedDict。它是用纯Python编写的,因此如果需要,您可以轻松地将其插入或修改为早期版本。

OrderedDict将保持插入顺序。

相关问题