我需要找到一组类的最后一个公共祖先,以便返回该类型。你知道吗
上下文,我正在做一些相当复杂的元程序,包括重载numpy功能。(不要问)我对一个函数有一个数量可变的参数,我已经将它的类型提取到一个集合中(过滤掉一些不相关的类型),使用这个信息,我需要找出类型树最下面的哪个部分,其中所有类型共享同一个基类型。我有一些首次通过的尝试,但我被多重继承等绊倒了。你知道吗
第一次通过:
def lca_type(types):
if len(types) == 1:
return types.pop()
filtered_types = set()
for type in types:
if not any(issubclass(type, x) for x in types):
filtered_types.add(type)
if len(filtered_types) == 1:
return filtered_types.pop()
# TODO: things get tricky here
考虑以下类层次结构:
class A(object):
pass
class B(A):
pass
class C(A):
pass
class D(A):
pass
class B1(B):
pass
class B2(B):
pass
class BC(C, B1):
pass
class CD(C, D):
pass
class D1(D):
pass
class BD(B, D):
pass
class B1_1(B1):
pass
预期结果:
lca_type({A,BD}) == A
lca_type({C}) == C
lca_type({B1,B2}) == B
lca_type({{B1_1, D}) == A
lca_type({CD, BD}) == D
lca_type({B1_1, BC}) == B1
您可以使用每个类的
mro
方法来获取祖先类的列表。将祖先列表映射到collections.Counter
,这样就可以对它们使用&
操作符来获取公共祖先,同时保持键顺序,有效地模拟获取有序集的交集。然后对聚集的Counter
对象的键的祖先序列使用next
函数来获取最近的祖先:所以下面的表达式都是
True
:请注意,键顺序仅为Python 3.7+维护,因此对于以前的Python版本,可以使用重用
Counter
属性的collections.OrderedDict
子类替换Counter
:取所有共同祖先的集合,使用简单的最小算法来查找最低的共同祖先,然后验证它实际上是最新的:
使用一个简单的最小值看起来可能有问题,但它实际上是好的,即使是在多重继承中。如果有一个明确的最低共同祖先,那么它是
all_common_ancestors
(包括它本身)的每个元素的子类,因此我们将在到达它时将candidate
设置为最低共同祖先,然后再也不会更改candidate
。如果没有明确的最低公共祖先,那么无论candidate
以循环结尾结束,它都不会通过验证检查。你知道吗更棘手的部分是处理
__subclasscheck__
/__subclasshook__
覆盖。我认为这个实现应该足够健壮,可以处理大多数常见的ABC情况,但是当任意的__subclasscheck__
实现使得issubclass
定义的图甚至不是DAG时,最低公共祖先的整个概念就变得奇怪了。你知道吗相关问题 更多 >
编程相关推荐