使用共享变量重构嵌套循环

Refactoring nested loop with shared variables

我有一个函数可以使用嵌套循环处理一些非常嵌套的数据。它的简化结构是这样的:

def process_elements(root):
    for a in root.elements:
        if a.some_condition:
            continue
        for b in a.elements:
            if b.some_condition:
                continue
            for c in b.elements:
                if c.some_condition:
                    continue
                for d in c.elements:
                    if d.some_condition:
                        do_something_using_all(a, b, c, d)

这对我来说看起来不是很pythonic,所以我想重构它。我的想法是在多个函数中分解它,比如:

def process_elements(root):
    for a in root.elements:
        if a.some_condition:
            continue
        process_a_elements(a)
        
def process_a_elements(a):
    for b in a.elements:
        if b.some_condition:
            continue
        process_b_elements(b)
        
def process_b_elements(b):
    for c in b.elements:
        if c.some_condition:
            continue
        process_c_elements(c)
        
def proccess_c_elements(c):
    for d in c.elements:
        if d.some_condition:
            do_something_using_all(a, b, c, d) # Problem: I do not have a nor b!

如您所见,对于嵌套更多的级别,我需要使用其所有“父”元素做一些事情。这些函数将具有独特的范围,因此我无法访问这些元素。将所有前面的元素传递给每个函数(比如 proccess_c_elements(c, a, b))对我来说确实很难看而且也不是很 pythonic...

有什么想法吗?

我不知道确切的数据结构和代码的复杂性,但您可以尝试使用列表将对象引用传递给下一个菊花链函数,如下所示:

def process_elements(root):
    for a in root.elements:
        if a.some_condition:
            continue
        listobjects=[]
        listobjects.append(a)
        process_a_elements(a,listobjects)
        
def process_a_elements(a,listobjects):
    for b in a.elements:
        if b.some_condition:
            continue
        listobjects.append(b)
        process_b_elements(b,listobjects)

def process_b_elements(b,listobjects):
    for c in b.elements:
        if c.some_condition:
            continue
        listobjects.append(c)
        process_c_elements(c,listobjects)
        
def process_c_elements(c,listobjects):
    for d in c.elements:
        if d.some_condition:
            listobjects.append(d)
            do_something_using_all(listobjects)

def do_something_using_all(listobjects):
    print(listobjects)

FWIW,我找到了一个解决方案,将所有处理封装在一个 class 中,并具有跟踪当前处理的元素的属性:

class ElementsProcessor:
    def __init__(self, root):
        self.root = root
        
        self.currently_processed_a = None
        self.currently_processed_b = None
        
    def process_elements(self):
        for a in self.root.elements:
            if a.some_condition:
                continue
            self.process_a_elements(a)
            
    def process_a_elements(self, a):
        self.currently_processed_a = a
        for b in a.elements:
            if b.some_condition:
                continue
            self.process_b_elements(b)
            
    def process_b_elements(self, b):
        self.currently_processed_b = b
        for c in b.elements:
            if c.some_condition:
                continue
            self.process_c_elements(c)
    
    def process_c_elements(self, c):
        for d in c.elements:
            if d.some_condition:
                do_something_using_all(
                    self.currently_processed_a,
                    self.currently_processed_b,
                    c,
                    d
                )