我在Python 2.5中有一个类和类型的注册表,如下所示:
class ClassA(object):
pass
class ClassB(ClassA):
pass
MY_TYPES = {
basestring : 'A string',
int : 'An integer',
ClassA : 'This is ClassA or a subclass',
}
我希望能够将类型传递给函数,并让它在层次结构中查找最接近的匹配类型。因此,查找str
将返回"A string"
并查找ClassB
将返回"This is ClassA or a subclass"
问题是,我不知道如何找到超类(或者更确切地说,跟踪类型对象的MRO链。
处理此问题的最佳方式是什么?
答案 0 :(得分:4)
from inspect import getmro
[st for cls, st in MY_TYPES.items() if cls in getmro(ClassB)]
['This is ClassA or a subclass']
或者如果您只对第一个匹配生成器版本感兴趣:
(st for cls, st in MY_TYPES.iteritems() if cls in getmro(ClassB))
答案 1 :(得分:2)
要获取课程的超类,请使用__bases__
:
class ClassA(object):
pass
class ClassB(ClassA):
pass
print ClassB.__bases__
(<class '__main__.ClassA'>,)
谨防int
之类的事情。所有这些的基础将是<type 'object'>
。您必须进行一些测试和迭代才能匹配您在示例中列出的dict键。
另一种选择是在任何对象实例上使用isinstance
,或在参数上使用issubclass
,对每个对象键进行测试。有些人认为isinstance
及其同类是魔鬼的标志,但是你可以看到。但是,请注意使用带有整数和其他此类类型的issubclass
。你可能需要结合使用dict键的几种方法。
答案 2 :(得分:1)
(st为cls,st为MY_TYPES.iteritems(),如果是getmro(ClassB)中的cls)
更简单的写作方式是:
(st for cls, st in MY_TYPES.iteritems() if issubclass(ClassB, cls))
然而,这并没有找到“最近”的匹配;如果“对象”在查找中,它可以匹配所有内容!如果您在查找中有其他东西的子类,或者您想支持多重继承,那么您必须选择MRO中第一个的那个:
for cls in inspect.getmro(ClassB):
if cls in MY_TYPES:
print MY_TYPES[cls]
break
else:
print 'Dunno what it is'
无论如何......我通常认为类型查找只是一点代码味道,没有更好的方法可以做你想要的吗?
答案 3 :(得分:0)
这实际上是通用功能的工作。请参阅PEAK-Rules和PEP 3124。通用函数允许您根据参数类型或甚至更复杂的表达式调度任意函数。
或者,如果你真的是一个惩罚的傻瓜,请见chapter的Practical Common Lisp {/ 3}}。