Python - 遍历嵌套对象

4
什么是Python中迭代嵌套对象的优雅方式?目前我正在使用以下嵌套循环。
for job in jobs:
    for task in job.tasks:
        for command in task.commands:
            print command.actual_cmd

有更符合 Python 编程规范的方法吗?


你正在覆盖任务。 - luigigi
2
除了删除错误(for command in task.commands: print command.actual_cmd)之外,你所写的代码没有任何问题,除非你有许多不同的对象结构,并且这些结构中有类似的循环,那么你可以编写一个更通用的函数。但是,由于你只是在打印输出,这种情况似乎不太可能发生。 - Grismar
看起来很Pythonic! - Brett La Pierre
2个回答

3
你可以设置链接的生成器来保持缩进级别不变。
iter_tasks = (task for job in jobs for task in job.tasks)
iter_commands = (command for task in iter_tasks for command in task.commands)

for command in iter_commands:
    print(command.actual_cmd)

我赞同OldBunny2800的看法,即在三个嵌套循环的情况下,链接生成器可能不会提高代码可读性。

如果你的嵌套逻辑比这更深,那么生成器就开始变得有吸引力了。它不仅可以保持缩进级别,还可以为每个生成器分配一个有意义的变量名,有效地给for循环起个名字。


3
我不同意,我认为与使用嵌套生成器相比,OP的代码一眼看上去更容易阅读。 - AAM111
2
@OldBunny2800 或许可以用三个嵌套循环实现,但不能用十个。 - timgeb

3

它是Pythonic的。已经是了。

但是,如果您担心这个嵌套层数可能会超过10层,并且只有最内层循环有任何有趣的内容,可以考虑创建一个生成器。您的代码可以变成:

def get_command(jobs):
    for job in jobs:
        for task in job.tasks:
            for command in task.commands:
                yield command

for command in get_command(jobs):
    print command.actual_cmd

因此,整个目的是为了避免过多的缩进。

使其适用于多层次,这样即使深入100层以上也不必担心:

def get_nested(objlist, attribs):
    for x in objlist:
        if len(attribs) == 0:
            yield x
        else:
            x_dot_attr = getattr(x, attribs[0])
            for y in get_nested(x_dot_attr, attribs[1:]):
                yield y

for command in get_nested(jobs, ["tasks", "commands"]):
    print command.actual_cmd

但是,这种概括并不能使代码更具Python风格,它只是避免了过度缩进。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接