2

I need to write a function (say fun1) that has one argument, because it will be used in other function (fun2). The latter requires a function with a single argument. However, I need to pass other parameters to function fun1. How can I do this in Python without using global variables? Or this is the only way?

Addition: If it is important, fun2 is some optimization function from scipy.optimize. Below is an example of passing additional parameter c to function fun1 using global. In the first call, function fun2 takes fun1 as x+1, but in the second call, fun1 is x+2. I would like to make similar, but without using global. Hopefully, the example clarifies the question. (The example is changed).

def fun1(x) :
   global c
   return  x + c

def fun2(f1, x) :
   return  f1(x)

# main program
global c
x0= 1  
c= 1;   y= fun2(fun1, x0);  print(y)    # gives 2
c= 2;   y= fun2(fun1, x0);  print(y)    # gives 3
4
  • 1
    arguments are parameters.. Commented Jun 7, 2013 at 12:18
  • Please provide some concrete example or code. Commented Jun 7, 2013 at 12:45
  • That's better. I had updated my answer. Commented Jun 7, 2013 at 14:13
  • @MartijnPieters Strictly spoken, no. The arguments are the concrete values, the parameters are the "function-side" stuff. So above, the arguments fun1 and x0 are assigned to the parameters f1 and x. Commented Nov 25, 2013 at 19:11

5 Answers 5

4

If I've understood your question correctly, there are quite a number of ways to do what you want and avoid using global variables. Here they are.

Given:

x0 = 1
def fun2(f1, x):
    return f1(x)

All of these techniques accomplish your goal:

#### #0 -- function attributes
def fun1(x):
    return x + fun1.c

fun1.c = 1;  y = fun2(fun1, x0);   print(y)   # --> 2
fun1.c = 2;  y = fun2(fun1, x0);   print(y)   # --> 3

#### #1 -- closure
def fun1(c):
    def wrapper(x):
        return x + c
    return wrapper

y = fun2(fun1(c=1), x0);   print(y)   # --> 2
y = fun2(fun1(c=2), x0);   print(y)   # --> 3

#### #2 -- functools.partial object
from functools import partial

def fun1(x, c):
    return x + c

y = fun2(partial(fun1, c=1), x0);   print(y)   # --> 2
y = fun2(partial(fun1, c=2), x0);   print(y)   # --> 3

#### #3 -- function object (functor)
class Fun1(object):
    def __init__(self, c):
        self.c = c
    def __call__(self, x):
        return x + self.c

y = fun2(Fun1(c=1), x0);   print(y)   # --> 2
y = fun2(Fun1(c=2), x0);   print(y)   # --> 3

#### #4 -- function decorator
def fun1(x, c):
    return x + c

def decorate(c):
    def wrapper(f):
        def wrapped(x):
            return f(x, c)
        return wrapped
    return wrapper

y = fun2(decorate(c=1)(fun1), x0);   print(y)   # --> 2
y = fun2(decorate(c=2)(fun1), x0);   print(y)   # --> 3

Note that writing c= arguments wasn't always strictly required in the calls -- I just put it in all of the usage examples for consistency and because it makes it clearer how it's being passed.

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

1 Comment

You're welcome. That's a good one to use and has the advantage that it's very explicit (self documenting) about what's going on.
2

The fact that that function can be called even without those other parameters suggests, that they are optional and have some default value. So you should use default arguments.

def fun1(foo, bar='baz'):
    # do something

This way you can call function fun1('hi') and bar will default to 'baz'. You can also call it fun1('hi', 15).

If they don't have any reasonable default, you can use None as the default value instead.

def fun1(foo, bar=None):
    if bar is None:
        # `bar` argument was not provided
    else:
        # it was provided

3 Comments

This is not what I ment. In your case, if you call function fun1 with one argument, then the second argument bar can have only the default value (bar = 'baz'). I want to change the second argument as well, while calling the function fun1 with only a single argument.
@user2320292 you want to pass an argument without passing it? your question is not clear.
@user2320292 Well, ok, next guess. Maybe you are lookng for partial?
2

What you are looking for is a method in a class.

you define a class, with a method fun1 and an instance variable c. it is accessed from anywhere using the . notation:

class A:
    def fun1(self, x):
        return x + self.c

Let's define fun2, for the example:

def fun2(f, p):
    return f(p)

We can now use a.c it like you did with the global varaible c:

>>> a = A() # create an instance and initialize it
>>>         # "self.c" is undefined yet
>>>
>>> a.c = 1 # "self.c" will be 1
>>> fun2(a.fun1, 1)
2
>>> a.c = 2 # now "self.c" will be 2
>>> fun2(a.fun1, 1) # same arguments, different result
3

Here you can learn more about classes.

4 Comments

Yes, this is how I understand the (badly-worded) question. He wants to modify the behaviour of fun1 in advance of passing it to fun2, and as such it seems that passing an object would be the way to achieve it...
@Elazar: Thank you for answer. The answer looks a little bit complicated.
@user2320292 well, it isn't. it's your very function, put into a class. the examples are yours too. I'll clean it up a bit
@Tom: A variation of putting fun1() into class as shown here is to make it a class whose instances are callable -- sometimes called a functor -- as illustrated in #3 of my answer.
1

Just add the extra parameters with default values:

def fun1(param1, param2=None, param3=None):
    ...

Then you can call fun1 from fun2 like this:

def fun2():
    something = fun1(42)

And from somewhere else you can call it like this:

fun1(42, param2=60)

Comments

0

You may use the decorators to pass it the very decorators:

def jwt_or_redirect(fn):
  @wraps(fn)
  def decorator(*args, **kwargs):
    ...
    return fn(*args, **kwargs)
  return decorator

def jwt_refresh(fn):
  @wraps(fn)
  def decorator(*args, **kwargs):
    ...
    new_kwargs = {'refreshed_jwt': 'xxxxx-xxxxxx'}
    new_kwargs.update(kwargs)
    return fn(*args, **new_kwargs)
  return decorator

and the final function:

@jwt_or_redirect
@jwt_refresh
def home_page(*args, **kwargs):
  return kwargs['refreched_jwt']

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.