Python 数据模型中任意深度的所有对象的递归列表?

Python 数据模型中任意深度的所有对象的递归列表?,python,python-3.x,recursion,Python,Python 3.x,Recursion,假设我有一个由Python中的对象组成的数据结构,如下所示: class Planet: def __init__(self, name): self.name = name self.continents = [] class Continent: def __init__(self, name): self.name = name self.countries = [] class Country:

假设我有一个由Python中的对象组成的数据结构,如下所示:

class Planet:
    def __init__(self, name):
        self.name = name
        self.continents = []

class Continent:
    def __init__(self, name):
        self.name = name
        self.countries = []

class Country:
    def __init__(self, name):
        self.name = name
        self.states = []

class State:
    def __init__(self, name):
        self.name = name
        self.cities = []

class City:
    def __init__(self, name):
        self.name = name
现在假设我要创建一个函数,该函数能够将一个对象和一个属性“path”作为参数,并输出与该路径“匹配”的所有对象的列表。由于我真的不知道如何很好地描述我的想法,而且很可能我使用了错误的术语,下面是一个关于它在实践中可能是什么样子的想法(让我们调用函数
collect
,并假设数据结构中填充了数据,
planet
是“根”数据结构的对象):

这个函数调用将返回地球上每个大陆每个国家每个州每个城市的列表。或者,如果我想要数据模型中的所有状态,我会:

collect(planet, "continents.countries.states")
希望你能明白。问题是我根本不知道如何才能做到这一点。以下是我到目前为止的想法:

def collect(obj, attr_path):
    attrs = attr_path.split(".")
    current_attr = obj
    items = []
    for attr in attrs:
        current_attr = getitem(current_attr, attr)
        # Not sure what to do here...
    return items

有人知道我如何做到这一点吗?

如果您想进行广度优先搜索:

def bfs(queue, results):
    try:
        obj, attr_path = queue.pop(0)
    except IndexError:
        return

    if attr_path is None:
        results.append(obj)
    else:
        if '.' in attr_path:
            first, rest = attr_path.split('.', maxsplit=1)
        else:
            first, rest = attr_path, None

        children = getattr(obj, first)
        for child in children:
            queue.append((child, rest))

    bfs(queue, results)

def collect(obj, attr_path):
    queue = [(obj, attr_path)]
    results = []
    bfs(queue, results)
    return results

免责声明:未经测试

您描述的内容与或类似。pypi中有几个JSONPath包。我建议你看看。
def bfs(queue, results):
    try:
        obj, attr_path = queue.pop(0)
    except IndexError:
        return

    if attr_path is None:
        results.append(obj)
    else:
        if '.' in attr_path:
            first, rest = attr_path.split('.', maxsplit=1)
        else:
            first, rest = attr_path, None

        children = getattr(obj, first)
        for child in children:
            queue.append((child, rest))

    bfs(queue, results)

def collect(obj, attr_path):
    queue = [(obj, attr_path)]
    results = []
    bfs(queue, results)
    return results