Harit Vishwakarma
Harit Vishwakarma

Reputation: 2441

Python: Passing function with arguments to a function

I have two functions:

  1. library function which I cannot change say lib_func( func, param1)
    i.e. lib_func takes a function func and some other parameter param1 as arguments.

  2. user defined function user_func.

For example:

x = 0
y = 0
def user_func():
    global x
    global y 
    return sqrt(x*y)

Now the problem is I want to pass x to user_func as argument not as globals while passing user_func to lib_func.

Upvotes: 3

Views: 1343

Answers (4)

MSeifert
MSeifert

Reputation: 152637

A function is simply an object that can be called so defining a class with a __call__ method is in principle equivalent to defining a function. At least in the context you are giving.

So:

def user_func(x, y, z):
    return anything_with(x, y, z)

is equivalent to:

class user_class(object):
    @staticmethod # staticmethod so that it can be called on the class
    def __call__(x, y, z):
        return anything_with(x, y, z)

as it stands this is just obfuscation. But the magic happens when you create an instance with predefined attributes and you only specifiy the variable arguments as parameters for the call:

class user_class(object):
    def __init__(self, x):
        self.x = x

    def __call__(self, y, z): # No x as parameter!
        return do_anything_with(self.x, y, z) # use the predefined x here

but you need to alter the way you call lib_func then:

x = 0
user_class_instance = user_class(0)
result = lib_func(user_class_instance, param1)

So it will repeat to call the instance with different y and z but x will be kept constant


Most of such lib_func functions however allow passing variable parameters (such that will be given to the user_func), for example scipy.optimize.curve_fit:

curve_fit(user_func, x, y, [initial_guess_param1, param2, ...])

there user_func will be called by curve_fit internally (you don't have to do anything!) like:

user_func(x, initial_guess_param1, param2, ...)
# Then curve-fit modifies initial_guess_param1, param2, ... and calls it again
user_func(x, initial_guess_param1, param2, ...)
# and again modifies these and calls again
user_func(x, initial_guess_param1, param2, ...)
# ... until it finds a solution

there x and y are defined and not changed when calling curve_fit but initial_guess_param1 will be changed while finding the optimal curve_fit .

Upvotes: 3

Mitchell Chu
Mitchell Chu

Reputation: 137

try to wrap the user_func and return a new function for lib_func:

def wrapuserfunc(x):
    user_func.x = x
    return user_func

def user_func():
    if hasattr(user_func, 'x'):
        print user_func.x

lib_func(wrapuserfunc(1), param1)  # user_func.x = 1
# get x in user_func
print user_func.x  # x = 1

wrapuserfunc(x) works fine. Function is object in Python.

Upvotes: -2

Mikhail Gerasimov
Mikhail Gerasimov

Reputation: 39546

If I understood task correctly, you'll need two things:

  1. create new function to wrap user_func with x, y params

  2. use functools.partial to get one more function with passed params

Here's example.

Module user_module.py where user_func defined:

x = 0
y = 0
def user_func():
   global x
   global y 
   print('user_func', x, y)

Module main.py where you need job done:

def lib_func(func, param1):
    print('lib_func', param1)
    func()


# Create user_func with params:
import user_module

def new_user_func(x, y):
    user_module.x = x
    user_module.y = y
    user_module.user_func()


# Use functools.partial to create user_func with ready params:
from functools import partial

f = partial(new_user_func, 1, 2)
lib_func(f, 'param1')

f = partial(new_user_func, 3, 4)
lib_func(f, 'param1')

Output for this example:

lib_func param1
user_func 1 2

lib_func param1
user_func 3 4

Upvotes: 1

Hannes Ovrén
Hannes Ovrén

Reputation: 21831

You can wrap your user_func() with another function

def parameterized_func(local_x):
    global x
    x = local_x
    return user_func()

And then pass the new parameterized_func() function to your lib_func(). This is not very nice, and will obviously change the global x variable. I would suggest looking into and see if you can't change the user_func() function instead.

Upvotes: 1

Related Questions