1

I want to define a wrapper function that wraps up a number of other functions with many arguments and want to use the magic variables in the wrapper function.

For example, suppose I have these three functions:

def function1(ret, ben, period=0, **kwargs):
 return ret, ben, period


def function2(ret, ben, risk_free=0, **kwargs):
 return ret, ben, risk_free

def function3(ret, ben, rf=0, **kwargs):
 return ret, ben, rf

And I want to wrap these functions with another function and use the magic variables so I can keep track of all possible arguments that each function might take.

I have tried something like this:

def wrapper_function(ret, ben, **kwargs):

  out1 = function1(ret, ben, **kwargs)
  out2 = function2(ret, ben, **kwargs)
  out3 = function3(ret, ben, **kwargs)

  return out1, out2, out3 

but this obviously fails because let's say, function1 does not have the same arguments as, for example, function2.

For example, if I call the wrapper function with wrapper_function(ret, ben, rf ) it will fail because functions1 and function2 don't have rf as their arguments.

My scope is essential to have a function that does something like this:

def wrapper_function(ret, ben, **kwargs1,**kwargs2,**kwargs3):

  out1 = function1(ret, ben, **kwargs1)
  out2 = function2(ret, ben, **kwargs2)
  out3 = function3(ret, ben, **kwargs3)

  return out1, out2, out3

This does not seem to work in python, however.

Any idea on how to use the magic variable in the wrapper function so no matter what arguments the functions inside it have it would work?

S.B
  • 13,077
  • 10
  • 22
  • 49
msh855
  • 1,493
  • 1
  • 15
  • 36
  • 1
    "this obviously fails" No, that should work. If it fails, you'll need to elaborate how. – Sören May 02 '22 at 07:52
  • @Sören I said why it fails 'functions don't have the same arguments', so If I call wrapper_function(ret, ben, rf ) it will fail because `functions1` and `function2` don't have `rf` as an argument. – msh855 May 02 '22 at 08:08
  • right, sorry about that. – Sören May 02 '22 at 08:22
  • @Sören No worries. In any case, I found it useful to elaborate. Please let me know if you have any ideas. – msh855 May 02 '22 at 08:23
  • "For example, if I call the wrapper function with wrapper_function(ret, ben, rf ) it will fail because functions1 and function2 don't have rf as their arguments." And even worse - they are missing one of *their* required arguments. Where do you imagine this argument comes from? – Sören May 02 '22 at 08:24
  • Good question. Assume that other arguments might have defaults set. so `rf = 0` or something. – msh855 May 02 '22 at 08:27

4 Answers4

3

With the help of getfullargspec, You can see what arguments your individual functions need, then get those from kwargs and pass them to the functions.

def wrapper_function(ret, ben, **kwargs):
    fns = (function1, function2, function3)
    results = []

    for fn in fns:
        fn_args = set(getfullargspec(fn).args)
        fn_required_args = fn_args - {'ret', 'ben'}

        required_dict = {
            item: kwargs[item] for item in fn_required_args if item in kwargs
        }
        results.append(fn(ret, ben, **required_dict))

    return results

Here is a complete code for test:

from inspect import getfullargspec


def function1(ret, ben, period=0):
    return ret, ben, period


def function2(ret, ben, risk_free=0):
    return ret, ben, risk_free


def function3(ret, ben, rf=0):
    return ret, ben, rf


def wrapper_function(ret, ben, **kwargs):
    fns = (function1, function2, function3)
    results = []

    for fn in fns:
        fn_args = set(getfullargspec(fn).args)
        fn_required_args = fn_args - {'ret', 'ben'}

        required_dict = {
            item: kwargs[item] for item in fn_required_args if item in kwargs
        }
        results.append(fn(ret, ben, **required_dict))

    return results


print(wrapper_function(10, 20, period=11, risk_free=22))

output:

[(10, 20, 11), (10, 20, 22), (10, 20, 0)]

note: If you don't want to hardcode this:

fn_required_args = fn_args - {'ret', 'ben'}

You can get the {'ret', 'ben'} part, from this expression:

set(getfullargspec(wrapper_function).args)
S.B
  • 13,077
  • 10
  • 22
  • 49
1

Actually, there is a way via introspection (the inspect module). Rough sketch below:

import inspect

def wrapper(ret, ben, **kwargs):
    fun1_argnames = inspect.getargspec(function1).args  # get valid args for function1
    theargs = {key: kwargs[key] for key in fun1_argnames}
    function1(**theargs)

However, this is getting a bit into 'hack' territory. I have never needed such a trick. I have a feeling that your problem could probably be solved in a different way (i.e. do you really need to wrap a huge amount of different functions with a huge amount of different arguments?)

Jussi Nurminen
  • 2,257
  • 1
  • 9
  • 16
0

If I understand the question correctly, you can just pick the relevant arguments out from the kwargs dict:

def wrapper_function(ret, ben, **kwargs):

    out1 = function1(ret, ben, kwargs['period'])
    out2 = function2(ret, ben, kwargs['risk_free'])

Of course, you may want to first check if they actually exist in the kwargs, e.g.

period = kwargs['period'] if 'period' in kwargs else 0
Jussi Nurminen
  • 2,257
  • 1
  • 9
  • 16
-2

This may be useful:

function1(ret, ben, kwargs.get('period'))
...
Jiang
  • 27
  • 4