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 functionargNames
that takes one or more classes or functions as arguments and returns a set of argument names, usinginspect
and, recursively, calls to theargNames
attribute of the functions. I can then attach this toVideoFileChoiceWidget.__init__
(for instance), using:Anyone who wants to pass arguments on to
VideoFileChoiceWidget
usesfilterArgs
as outlined in the question. I have implemented this and it seems to work.Below, for reference, are my current definitions of
argNames
andfilterArgs
.