I'd say that this question is primary opinion based, but I'm kinda... bored so here's my take:
In these cases I always tend to give priority to readability by other users. We all know that code should be properly commented, explained, with lots of documentation around, right? But I also should go to the gym and yet, here I am, writing this from the coziness of my sofa (which I'm not planning to abandon until... mid-April, more or less, when the weather gets better).
To me, if other people are going to read your code, I think it's very important to take advantage of the fact that Python, if properly written can be very, very clear (it's almost like pseudo-code that runs, right?)
So in your case, I wouldn't even create this kind-of-wrapper function. I would have a module smoothing.py
containing all your smoothing functions. Not only that, I'd import the module (import smoothing
) as opposed to from smoothing import boxcar, gaussian
) so I can be very explicit on my calls:
if method == 'boxcar':
smoothing.boxcar(whatever whatever...)
# Someone reading this will be able to figure out that is an smoothing
# function from a module called `"smoothing"`. Also, no magic done with
# things like my_func = getattr(smoothing, method)... none of that: be
# clear and explicit.
# For instance, many IDEs allow you to navigate to the function's
# definition, but for that to work properly, the code needs to be explicit
elif method == 'gaussian':
smoothing.gaussian(whatever whatever...)
else:
raise ValueError(
'Unknown smoothing method "%s".'
' Please see available method in "%s" or add'
' a new smoothing entry into %s' % (
method,
os.path.abspath(smoothing.__file__),
os.path.abspath(__file__)
)
)
Something like that. Something that if someone receives an error, can quickly understand where and why is it happening.
Otherwise, if you still want to keep your structure, I'd say that, since you're always going to need your 'method', don't put that into your kwargs. Make it positional:
def smoothing(method, dataDf, selected_columns, kwargs):
if method == 'boxcar':
boxcar(dataDf, selected_columns, kwargs['arguments'])
elif method == 'gaussian':
gaussian(dataDf, selected_columns, kwargs['arguments'])
else:
raise NotImplementedError
Another thing you could do, is instead of having the possibility of having bad arguments in the kwargs
dict, force it to include the proper arguments (what if someone passes in kwarg['arguments']
the argument method=boxcar
but gives you kwarg['arguments']
for gaussian
? Don't let that even be possible (make it crash as soon as possible):
def smoothing(method, dataDf, selected_columns, **kwargs):
if method == 'boxcar':
assert 'variance' not in kwargs # If `boxcar` shouldn't have a "variance"
boxcar(dataDf, selected_columns, kwargs['windsize'])
elif method == 'gaussian':
gaussian(dataDf, selected_columns, kwargs['windsize'], kwargs['variance'])
else:
raise NotImplementedError
And always provide a proper message in your exceptions (give a proper explanation on your NotImplementedError
)
There's a lot of "magic" you can do with Python. That doesn't mean you have to do it. For instance, you could get a fairly similar behavior to what your implementation of the smoothing
function is doing by writing something like this:
def smoothing(dataDf, selected_columns, kwargs):
return globals().get(
kwargs.pop('method') or 'NOT_IMPLEMENTED_FOR_SURE!!',
lambda *_: (_ for _ in ()).throw(NotImplementedError())
)(dataDf, selected_columns, kwargs['arguments'])
But if someone else reads that... well... good luck to that person :-P