按对象的类型排序

Ric*_*eur 1 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)
Run Code Online (Sandbox Code Playgroud)

ChildClass从哪里继承ParentClass.问题是,由于它是一个字典,订单没有定义 - 但我如何内省类型对象来找出一个排序键

生成的顺序应该是超类的子类(首先是大多数特定类型).例如,str之前basestringChildClass之前ParentClass.如果类型不相关,那么它们相对于彼此的位置并不重要.

Ale*_*lli 5

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

def numberofancestors(klass):
    return len(klass.mro())
Run Code Online (Sandbox Code Playgroud)

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

import inspect

def numberofancestors(klass):
    return len(inspect.getmro(klass))
Run Code Online (Sandbox Code Playgroud)

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

sorted(HANDLERS, key=numberofancestors, reversed=True)
Run Code Online (Sandbox Code Playgroud)

会给你你需要的东西(你不需要这个.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]
Run Code Online (Sandbox Code Playgroud)

这个想法很好(如果多重继承支持是有意义的),但最好的实现可能是(Python 2.6或更高版本):

next(Handlers[c] for c in type(obj).mro() if c in Handlers)
Run Code Online (Sandbox Code Playgroud)

通常,adict.get(k) and check for not Noneif k in adict: adict[k]这更快,但这不是一个特别正常的情况,因为使用get需要构建"假的"单项列表并在其上"循环"以模拟分配.

更一般地说,通过理解建立一个完整的列表只是为了获取它的[0]项目 - 在nextgenexp上调用的内置函数更像是一个first,就像在"给我genexp的第一项"并且没有额外的工作除此之外.如果listcomp/genexp为空,它会引发StopIteration而不是IndexError,但这通常不是问题; next如果genexp为空,你还可以使用第二个参数作为"默认值".

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

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