我有代码在模块加载时静态注册(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
的位置。问题是,由于它是一个字典,订单没有定义 - 但如何内省类型对象以找出一个排序键?
结果顺序应该是子类,然后是超类(首先是大多数特定类型)。例如。 str
在basestring
之前,ChildClass
在ParentClass
之前。如果类型不相关,那么它们相对于彼此的位置并不重要。
答案 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()
部分)。
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 None
比if 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将保持插入顺序。