首页 > 解决方案 > 涉及类的递归函数

问题描述

def check_classes(cls):
    if len(cls.__bases__) == 0:
        return []
    else:
        test_list = []
        for x in range(len(cls.__bases__)):
            test_list += [cls] + check_classes(cls.__bases__[x])
        for x in cls.__bases__:
            return test_list + [x]

我目前有一个递归函数,它将一个类作为其参数并返回所有基类的列表。这工作正常,但它在列表中有许多重复的类。我想返回一个集合而不是一个列表,并且想知道如何更改代码来做到这一点。

标签: pythonclassrecursionset

解决方案


Python 有一个内置set类型可以消除重复:

def get_bases(obj):
   bases = {obj}  # new set including only obj
   if not(obj.__bases__):  # technically redundant - iter is a noop on empty collections
      return bases
   else:
      for x in obj.__bases__:
          bases.update(get_bases(x))  # update set - automatically eliminates duplicates
      return bases

这段代码一开始就避免了添加许多重复项。但是,在set多重继承的情况下仍然会消除重复。

class A: ...
class B1(A): ...
class B2(A): ...
class C(B1, B2): ...
print(get_bases(C))
# {<class '__main__.C'>, <class '__main__.B1'>, <class 'object'>, <class '__main__.B2'>, <class '__main__.A'>}

Python 是 Python,已经有一些东西可以做到这一点:

>>> C.__mro__
(__main__.C, __main__.B1, __main__.B2, __main__.A, object)

如果您只关心基础,请使用__mro__. 它的顺序还表示如何使用多个碱基执行查找。


这种搜索的一种稍微不同的方法是使用 aset跟踪重复项,但使用 alist存储元素:

def get_bases(obj, _dupes=None):
   _dupes = _dupes if _dupes is not None else set()
   bases = [obj]  # new list including only obj
   _dupes.add(obj)
   for x in obj.__bases__:
       if x not in _dupes:
           bases.extend(get_bases(x, _dupes))  # update set - automatically eliminates duplicates
   return bases

这使用 a_dupes: set检查您是否已经访问过课程。它不会消除您添加两次的类,而是首先添加一次。给定许多元素,此检查Aset比 a 更快。list但是,您需要list保留顺序。


推荐阅读