1

我正在尝试找到一种优雅的pythonic方法来解决以下问题。我有一个类,VideoAnalysisWidget创建一大堆子小部件,例如VideoFileChoiceWidgetRegionWidget等。我想VideoAnalysisWidget.__init__将任何适当的关键字参数传递给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']

...然后修改filterArgs以使用它(如果可用)。但是有没有更好,更蟒蛇的方式来做到这一点?

4

1 回答 1

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)
于 2014-11-27T18:21:23.270 回答