Python过滤* args ** kwargs

时间:2018-08-06 23:46:09

标签: python python-3.x wxpython

我正在用wxPython编写GUI,并正在创建用于显示终端窗口的自定义控件,因为我无法找到当前存在的窗口。

我的控件TerminalCtrl扩展到wx.Control上,并且我的init定义开始如下:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

我想强制执行以下样式:

style=wx.BORDER_NONE

也就是说,此窗口上不允许有边框。但是,我仍然愿意根据程序员的意愿允许使用 other 样式。

作为参考,__init__的{​​{1}}函数定义如下

wx.Control

我想要实现的是我可以过滤__init__ (self, parent, id=ID_ANY, pos=DefaultPosition, size=DefaultSize, style=0, validator=DefaultValidator, name=ControlNameStr) 参数以强制使用style样式。据我了解,根据参数是按位置传递参数还是通过具体引用参数名称(如{wx.BORDER_NONE),这可以在*args**kwargs中出现。

在将参数传递给style=wx.BORDER_NONE之前,是否可以通过标准/推荐/ pythonic方式对参数强制使用此类过滤器?如果可以,该如何实现?

1 个答案:

答案 0 :(得分:1)

最干净的方法可能只是复制基类的签名:

def __init__(self, parent, id=ID_ANY, pos=DefaultPosition,
             size=DefaultSize, style=0, validator=DefaultValidator,
             name=ControlNameStr):
    style |= wx.BORDER_NONE
    super().__init__(parent, id, pos, size, style, validator, name)

如果您对一堆类的构造签名都具有一堆位置或关键字参数的类执行此操作,则可能会有些麻烦。或者,如果您要针对定期更改的API进行操作。

在这种情况下,您始终可以使用inspect动态地做到这一点:

_wxControlSig = inspect.signature(wx.Control)

class TerminalCtrl(wx.Control)
    def __init__(self, *args, **kwargs):
        bound = _wxControlSig.bind(*args, **kwargs)
        bound.apply_defaults()
        bound.arguments['style'] |= wx.BORDER_NONE
        super().__init__(*bound.args, **bound.kwargs)

如果要执行许多操作,则可能需要编写装饰器来提供帮助。而且,您可能还想应用functools.wraps或手动执行等效操作以使您的签名变得自省。 (而且,如果您没有做很多这样的事情,您可能只想露骨,如答案顶部的示例所示。)


如果您的内容有些重复且令人讨厌而无法明确地做,但是不值得内省地发疯,则介于两者之间的唯一一件事就是明显的hacky,例如:

def __init__(self, *args, **kwargs):
    if len(args) > 3:
        args = list(args)
        args[3] |= WX_BORDER_NONE
    elif 'style' in kwargs:
        kwargs['style'] |= wx.BORDER_NONE
    else:
        kwargs['style'] = wx.BORDER_NONE
    super().__init__(*args, **kwargs)

对于Python 2.x(或3.0-3.2),您没有signature,只有getargspec和朋友,这可能很诱人。但是对于3.3+版本,避免使用signature的唯一原因是可以优化出几纳秒的时间。并且当所讨论的功能是涉及与系统窗口管理器对话的小部件的构造函数时,担心这将很愚蠢。