pskeshu
pskeshu

Reputation: 219

Pythonic way to write nested for loops

I'm trying to iterate through multiple generators that are dynamically generated, in the order as specified in the user code.

I want to modify run() so that it can support n number of tasks, as opposed to three as of now. I tried using itertools.product() but I'm not sure how to call next() on my generators one at a time.

I think I will have to use recursion here but I'm not sure how to proceed. Any points are greatly appreciated.

class ImageSeries:
    def __init__(self):
        self.tasks = []

    def xy(self, position):
        print(f"xy: {position}")
        yield "xy"

    def z(self, position):
        print(f"z: {position}")
        yield "z"

    def exp(self, exposure):
        print(f"exp: {exposure}")
        yield "exposure"

    def xy_scan(self, positions):
        self._xy_task = lambda: (self.xy(pos) for pos in positions)
        self.tasks.append(self._xy_task)
    
    def z_scan(self, positions):
        self._z_task = lambda: (self.z(pos) for pos in positions)
        self.tasks.append(self._z_task)

    def exp_scan(self, exposures):
        self._exp_task = lambda: (self.exp(e) for e in exposures)
        self.tasks.append(self._exp_task)

    def run(self):
        for generator_0 in self.tasks[0]():
            next(generator_0)
            for generator_1 in self.tasks[1]():
                next(generator_1)
                for generator_2 in self.tasks[2]():
                    next(generator_2)

    def __repr__(self):
        return str(self.self.tasks)


if __name__ == "__main__":
    s = ImageSeries()
    positions = [[0, 0], [100, 100], [1000, 1000]]
    s.xy_scan(positions)
    s.exp_scan([50, 100, 150])
    s.z_scan([0, 100, 1000, 10000])
    s.run()

My desired output is:

xy: [0, 0]
exp: 50
z: 0
z: 100
z: 1000
z: 10000
exp: 100
z: 0
z: 100
z: 1000
z: 10000
exp: 150
z: 0
z: 100
z: 1000
z: 10000
xy: [100, 100]
exp: 50
z: 0
z: 100
z: 1000
z: 10000
exp: 100
z: 0
z: 100
z: 1000
z: 10000
exp: 150
z: 0
z: 100
z: 1000
z: 10000
xy: [1000, 1000]
exp: 50
z: 0
z: 100
z: 1000
z: 10000
exp: 100
z: 0
z: 100
z: 1000
z: 10000
exp: 150
z: 0
z: 100
z: 1000
z: 10000

Upvotes: 1

Views: 79

Answers (2)

safiqul islam
safiqul islam

Reputation: 650

Here is the recursive function where n should be start with 0

def run(self,n):
    for generator in self.tasks[n]():
        next(generator)
        m=n+1
        if m < len(self.tasks):
            self.run(m)

Upvotes: 1

Yogaraj
Yogaraj

Reputation: 320

How about modifying the for loop in run method as below,

def get_task(self):
    for task in self.tasks:
        yield task()

def loop_over(self, generator_obj):
    for generator in generator_obj:
        next(generator)
    self.loop_over(self.get_task())    

def run(self):
    self.loop_over(self.get_task())

This will ensure that all the n number of tasks are called.

Upvotes: 1

Related Questions