2

I have a function that process some quite nested data, using nested loops. Its simplified structure is something like this:

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)

This does not look very pythonic to me, so I want to refactor it. My idea was to break it in multiple functions, like:

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!

As you can see, for the more nested level, I need to do something using all its "parent" elements. The functions would have unique scopes, so I couldn't access those elements. Passing all the previous elements to each function (like proccess_c_elements(c, a, b)) does look ugly and not very pythonic to me either...

Any ideas?

4
  • Can you give an example of the data/object you're trying to run this on? Commented Feb 15, 2022 at 9:03
  • The question is more about the concept than about the specific problem. The example is a very simplified version of it, the real data is a way more complicated. In fact, the "nested data" is a mix of Python objects, dicts and JSON arrays... Commented Feb 15, 2022 at 9:11
  • perhaps classes and inheritance? in case the ratio between a, b, c, d is appropriate to the inheritance concept Commented Feb 15, 2022 at 9:14
  • I think that is not feasible in this case. First, because in reality a, b, c and d are not just objects, I just put it that way to make the example clearer. But in fact, they are a mix of objects and dicts. Also, all having the same attributes (elements, some_condition) is a simplification for the example too. Second, because the data structure was not built by me. It comes from an external library out of my control. Commented Feb 15, 2022 at 9:23

2 Answers 2

1

I don't know the exact data structures and the complexity of your code but you may try to use a list to pass the object reference to the next daisy chained function something like the following:

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)
Sign up to request clarification or add additional context in comments.

5 Comments

Hummm, this would not work for this case, as it would create a list with all as, bs, cs and ds, and what I need to do is to do something with the a-b-c-d combinations.
No it won't add all a's b's and c's as it is only adding the ones that do not satisfy the "if" condition.
What I mean is that I need to use do_something_using_all with combinations of a-b-c-d. Not with a list of all as, bs, cs and ds that satisfy the condition.
Understood, but in my solution a new instance of list "listobjects" is created for each iteration of root.elements which means each time do_something_using_all is called, it will only have one combination of a, b, c and d. "listobjects" is not an object with global scope.
Yes, but I do not need to call it one time per iteration of root. I might need to do it per combination of a-b-c-d. However, your suggestion has given me an idea... I am going to make some tests and see if it works...
0

FWIW, I've found a solution, which is to encapsulate all the proccessing inside a class, and having attributes to track the currently processed elements:

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
                )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.