I am trying to find an elegant pythonic way to solve the following problem. I have a class, VideoAnalysisWidget, that creates a whole bunch of child widgets such as VideoFileChoiceWidget, RegionWidget, etc. I want VideoAnalysisWidget.__init__ to pass any appropriate keyword arguments to VideoFileChoiceWidget.__init__, RegionWidget.__init__, ... To accomplish this, I would like to use code like the following:
import inspect
def filterArgs(func, **kwargs):
spec = inspect.getargspec(func)
ks = set(kwargs.keys())
ks.discard('self')
kinc = ks & set(spec.args)
kexc = ks - set(spec.args)
inc = {k: kwargs[k] for k in kinc}
exc = {k: kwargs[k] for k in kexc}
return(inc, exc)
Then, elsewhere:
def __init__(self, **kwargs):
(fcwArgs, otherArgs) = filterArgs(VideoFileChoiceWidget.__init__, **kwargs)
fcw = VideoFileChoiceWidget(**fcwArgs)
...
Doing things this way, my code for VideoAnalysisWidget doesn't have to keep track of the argument list of VideoFileChoiceWidget. If I later revise VideoFileChoiceWidget to take a new argument, I don't need to make changes in the distant VideoAnalysisWidget code.
Now here's the problem. This works fine if VideoFileChoiceWidget has only explicitly defined keyword parameters. (BTW, I'm fine with not using any positional parameters other than self for any of these functions.) But what if VideoFileChoiceWidget also has a **kwargs argument? It does, in fact, because it's subclassed from ContainerWidget, so I want to pass any extra extra arguments on to that. (And ContainerWidget takes ONLY **kwargs.) Fundamentally, the problem is that this solution of mine can't be nested.
A possible solution would be to attach a list of additional arguments to VideoFileChoiceWidget.__init__, e.g.:
VideoFileChoiceWidget.__init__._args = ['description', 'visible', 'children']
...then modify filterArgs to use this if available. But is there a better, more pythonic way to do it?
I'm going ahead with a variant on the approach I outlined in my original post, in which I attach an attribute to
__init__. However, instead of making it a list, I am taking the more flexible approach of using a function. I define an unattached functionargNamesthat takes one or more classes or functions as arguments and returns a set of argument names, usinginspectand, recursively, calls to theargNamesattribute of the functions. I can then attach this toVideoFileChoiceWidget.__init__(for instance), using:Anyone who wants to pass arguments on to
VideoFileChoiceWidgetusesfilterArgsas outlined in the question. I have implemented this and it seems to work.Below, for reference, are my current definitions of
argNamesandfilterArgs.