我试图找到一种优雅的pythonic方法来解决以下问题。我有一个类VideoAnalysisWidget
,它创建了一大堆子窗口小部件,例如VideoFileChoiceWidget
,RegionWidget
等。我希望VideoAnalysisWidget.__init__
将任何适当的关键字参数传递给{ {1}},VideoFileChoiceWidget.__init__
,...为了实现这一目标,我想使用以下代码:
RegionWidget.__init__
然后,在其他地方:
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)
以这种方式做事,def __init__(self, **kwargs):
(fcwArgs, otherArgs) = filterArgs(VideoFileChoiceWidget.__init__, **kwargs)
fcw = VideoFileChoiceWidget(**fcwArgs)
...
的代码不必跟踪VideoAnalysisWidget
的参数列表。如果我稍后修改VideoFileChoiceWidget
以采取新的论点,我就不需要在远程VideoFileChoiceWidget
代码中进行更改。
现在问题出在这里。如果VideoAnalysisWidget
仅明确定义了关键字参数,则此方法可以正常工作。 (顺便说一下,我没有使用VideoFileChoiceWidget
以外的任何位置参数来处理这些函数。)但如果self
也有VideoFileChoiceWidget
参数怎么办?事实上,它确实是因为它是**kwargs
的子类,所以我想传递任何额外的参数。 (而且ContainerWidget
仅取ContainerWidget
。)从根本上说,问题是我的这个解决方案无法嵌套。
一种可能的解决方案是将附加参数列表附加到**kwargs
,例如:
VideoFileChoiceWidget.__init__
...然后修改VideoFileChoiceWidget.__init__._args = ['description', 'visible', 'children']
以使用此选项(如果可用)。但有没有更好,更pythonic的方式呢?
答案 0 :(得分:0)
我正在使用我原始帖子中概述的方法的变体,其中我将属性附加到__init__
。但是,我采用更灵活的方法来使用函数,而不是将其列为列表。我定义了一个未附加的函数argNames
,它使用一个或多个类或函数作为参数,并使用inspect
返回一组参数名称,并递归地调用函数的argNames
属性。然后我可以使用:
VideoFileChoiceWidget.__init__
(例如)
class VideoFileChoiceWidget(ContainerWidget):
...<stuff>...
def __init__(arg1, arg2, ..., **kwargs):
...<more stuff>...
__init__.argNames = lambda: (argNames(ContainerWidget) |
{'description', 'visible', 'children'})
任何想要将参数传递给VideoFileChoiceWidget
的人都会使用问题中所述的filterArgs
。我已经实现了它,它似乎工作。
以下是argNames
和filterArgs
的当前定义供参考。
def argNames(*args):
"""
Get the names of the argument for a function
Returns:
--------
A set whose members are the argument names
Parameters:
-----------
func1, func2, ... -- the functions to be analyzed. The arguments
are discovered by inspecting func. In addition, if
func.argNames is defined, it is called (without arguments) to
get a list of addition names. Any number of functions may be
listed. If func is a class, func.__init__ is used
instead. 'self' is always removed from the argument list.
"""
names = set({})
for a in args:
try:
func = a
spec = inspect.getargspec(func)
except TypeError:
func = a.__init__
spec = inspect.getargspec(func)
names |= set(spec.args)
try:
names |= set(func.argNames())
except AttributeError:
pass
names.discard('self')
return(names)
def filterArgs(func, **kwargs):
"""
Select keyword arguments for a function
"""
args = argNames(func)
ks = set(kwargs.keys())
ks.discard('self')
kinc = ks & args
kexc = ks - args
inc = {k: kwargs[k] for k in kinc}
exc = {k: kwargs[k] for k in kexc}
return(inc, exc)