3

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.

5
  • You can't modify user_func() too, right? Commented Mar 14, 2016 at 7:18
  • yes you can modify user_func Commented Mar 14, 2016 at 8:07
  • If you can modify user_func, what is the problem? Just stop using global variables! Commented Mar 14, 2016 at 15:47
  • @Hannes I guess you didn't get the question. Commented Mar 15, 2016 at 12:33
  • Apparently not. But you haven't explained why those globals are there and why they can't be removed if you have access to the function source. Commented Mar 15, 2016 at 12:36

4 Answers 4

3

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 .

Sign up to request clarification or add additional context in comments.

Comments

1

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.

2 Comments

But we still couldn't get rid of globals.
You can't really get rid of using globals unless you have permission/possibility to change user_func().
1

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

2 Comments

lib_func is going to call user_func repeatedly with new arguments.
@iota, just create new func with partial for each set of arguments. I updated answer to show it.
-2

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.

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.