Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping function call signatures consistent for a function that accepts a superset of another function's arguments

I have a function (foo) that is a convenience function wrapper for another function (bar). foo calls bar, then performs another couple of tasks on the output. For example:

def bar(bar_arg, bar_kw=None):
    #do some stuff
    return ret

def foo(bar_arg, foo_arg, bar_kw=None, foo_kw=None):
    ret = bar(bar_arg, bar_kw)
    ret.some_method(foo_arg, foo_kw=foo_kw)

I would like the call signature for foo to contain the keywords and arguments from bar so that a user inspecting foo knows what they can pass, however, I would like to avoid maintaining the full list of arguments myself since bar tends to change as the package it comes from is updated and its argument list is long. Since foo always calls bar with the full list of arguments and keywords that bar accepts, I don't see that I should need to maintain the list myself.

Is there a way to build the call signature for foo based on the call signature for bar? Additionally, is there a way to capture the inputs to foo in a dictionary or namespace so that I can easily separate the arguments and keywords used by foo from those used by bar?

Note, I know about *args and **kwargs. They leave the function signature ambiguous, though, and don't inform the user of what arguments and keyword arguments are allowed.

Edit: I should note that my use case is significantly more complex than this example. The external function being called (bar) is matplotlib.colorbar.ColorbarBase. The calling function (foo) is a class method for a plotting class that is used in numerous applications of my own that others are likely to use in the future. foo creates a colorbar, then performs additional work on the colorbar based on additional arguments and keywords that are not accepted by ColorbarBase.

like image 382
Vorticity Avatar asked Nov 09 '22 14:11

Vorticity


1 Answers

Since bar() wraps foo() which calls the ColorbarBase constructor, write a decorator around the foo() call. The decorator makes modifications to the arguments passed into bar before calling foo().

from matplotlib import pyplot
import matplotlib as mpl


def bar(f):
    def wrapper(*args, **kwargs):
        # Change args, kwargs for calling foo()
        f(*new_args,**new_kwargs)
        return
return wrapper


@bar
def foo(*new_args, **new_kwargs):
    return mpl.colorbar.ColorbarBase(*new_args, **new_kwargs)

For example, the following returns a ColorbarBase object to the caller give an initial set of parameters which are then modified by bar(). In this way the call signature for foo() is based on the call signature for bar().

fig = pyplot.figure(figsize=(8, 3))
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
cmap = mpl.cm.cool
norm = mpl.colors.Normalize(vmin=5, vmax=10)

ret = foo(ax1, 
          cmap=cmap,
          norm=norm,
          orientation='horizontal')
like image 77
hhbilly Avatar answered Nov 14 '22 22:11

hhbilly