conorc
conorc

Reputation: 55

Modularization of Python code with function specific parameters

My code contains multiple lines of a nested for loop . I wanted to try and reduce the amount of nested for loops being called by putting the code into its own function similar to the do_for_each function below. Within the nested for loop I want to call another function. Below is a working example:

def do_for_each(self, func, h, w, init_data):
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(x, y)
        return init_data

def calculate_land_neighbours(self, x, y):
        return self.lscape[x-1,y] + self.lscape[x+1,y] + self.lscape[x,y-1] + self.lscape[x,y+1]

ouput = self.do_for_each(self.calculate_land_neighbours, self.h+1, self.w+1, data)

However, my problem arises when the function called within do_for_each does not take parameters x or y but another variable. For instance a new function would look like:

def add_to_density_array(self, seed):
        if seed == 0:
            return 0
        else:
            return random.uniform(0, 5.0)

output2 = self.do_for_each(self.add_to_density_array, self.h+1, self.w+1, data, seed)

For this to run properly I would need to amend my do_for_each function to:

def do_for_each(self, func, h, w, init_data, seed):
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(seed)
        return init_data

Would anyone have any recommendations where I could keep the modularised code of the do_for_each function but call functions within do_for_each that do not have the same input parameters?

Upvotes: 0

Views: 223

Answers (3)

Samanvya Tripathi
Samanvya Tripathi

Reputation: 1

You can try out Overloading Functions, here is a possible solution. You can read more here - https://www.geeksforgeeks.org/python-method-overloading/

def do_for_each(self, func, h, w, init_data, seed=None):
    if seed==None:
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(x, y)
        return init_data
    else:
        for x in range(1, h):
            for y in range(1, w):
                init_data[x,y] = func(seed)
        return init_data

Upvotes: 0

Konrad Rudolph
Konrad Rudolph

Reputation: 546035

Fundamentally, your two do_for_each functions are just very different. They don’t really perform the same transformation at all — one changes matrix entries as a function of the x, y indices, and another doesn’t.

I would consider using a different abstraction here.

That said, you can make this work without changing the original do_for_each: pass a lambda that wraps add_to_density_array, instead of passing the latter directly:

add_to_density = lambda x, y: self.add_to_density_array(seed)
output2 = self.do_for_each(add_to_density, self.h+1, self.w+1, data)

Upvotes: 1

Aviv Yaniv
Aviv Yaniv

Reputation: 6298

You can use default parameter of seed as None and check if it exits and operate accordingly:

def do_for_each(self, func, h, w, init_data, seed=None):
    for x in range(1, h):
        for y in range(1, w):
            # If no seed provided
            if seed is None:
                init_data[x, y] = func(x, y)
            # Else, seed provided - use it
            else:
                init_data[x, y] = func(seed)
    return init_data

This has the advantage of backward compatibility with the "old" do_for_each(self, func, h, w, init_data).

Upvotes: 0

Related Questions