Practical Motivation
Quite often I need to write functions that pass arguments to several subfunctions. Illustrative example:
def cristmas_with_family(gift_to_mom, gift_to_dad):
...
give_presents('mom', *gift_to_mom)
give_presents('dad', *gift_to_dad)
...
Ok, maybe more practical example:
def make_figure(X, Y, args_for_x_axis=(), args_for_y_axis=()):
...
draw_x_axis(*args_for_x_axis)
draw_y_axis(*args_for_y_axis)
...
This all works quite elegant, until I need to pass both named and unnamed args. Currently, I have to do something like this
def make_figure(X, Y, args_for_x_axis=(), args_for_y_axis=(), kwargs_for_x_axis={}, kwargs_for_y_axis={}):
...
draw_x_axis(*args_for_x_axis, **kwargs_for_x_axis, )
draw_y_axis(*args_for_y_axis, **kwargs_for_y_axis, )
...
or
def make_figure(X, Y, args_for_x_axis=(), args_for_y_axis=()):
...
match args_for_x_axis:
case ([*args], {**kwargs}):
draw_x_axis(*args, **kwargs)
case [*args]:
draw_x_axis(*args)
case {**kwargs}:
draw_x_axis(**kwargs)
match args_for_y_axis:
case ([*args], {**kwargs}):
draw_y_axis(*args, **kwargs)
case [*args]:
draw_y_axis(*args)
case {**kwargs}:
draw_y_axis(**kwargs)
...
Way less elegant!
(Note: using {}
as a default value is maybe not very safe since it is mutable, but this is just an illustration)
Suggested solution
Would it be nice to have a single object that would be unpackable to both named and unnamed args? Lets say unpacking can be made using ***
syntax (*
for unpacking iterables + **
for unpacking mappings). Something like arg this:
def make_figure(X, Y, args_for_x_axis=(), args_for_y_axis=()):
...
draw_x_axis(***args_for_x_axis)
draw_y_axis(***args_for_y_axis)
...
# calling the function
make_figure(X, Y, args_for_x_axis=ListDict(None), args_for_y_axis=ListDict(name='n of pirates by year', col='red'))