代码之家  ›  专栏  ›  技术社区  ›  Shane

Python在*args**kwargs中过滤参数

  •  1
  • Shane  · 技术社区  · 7 年前

    我在WxPython中编写了一个GUI,我正在创建一个显示终端窗口的自定义控件,因为我还没有找到一个当前存在的窗口。

    我的控制 TerminalCtrl 延伸到 wx.Control ,我的init定义如下所示:

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

    我想强制执行以下样式:

    style=wx.BORDER_NONE
    

    也就是说,这个窗口永远不允许有边界。不过,我还是想允许 其他 要应用的样式,由程序员决定。

    作为参考 __init__ 功能 wx.控制 定义如下

    __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 ).

    在将参数传递给 wx.Control.__init__ 如果是这样的话,我该怎么做呢?

    1 回复  |  直到 7 年前
        1
  •  1
  •   abarnert    7 年前

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

    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 或者手动执行相同的操作以使签名可内省。(如果你没有做很多这样的事情,你可能只想明确一点,如答案顶部的例子所示。)


    如果你有一件事情太过重复和烦人,不能明确地去做,但不值得去疯狂的反省,唯一的事情是在这两者之间的明确黑客,如:

    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+,唯一要避免的原因 签名 会优化出几纳秒。当所讨论的函数是涉及到与系统窗口管理器对话的小部件的构造器时,这种担心是非常愚蠢的。