【问题标题】:How to Extend Large Class Methods?如何扩展大类方法?
【发布时间】:2016-03-05 22:24:54
【问题描述】:

如果您想扩展一个类及其各自的__init__ 方法,有没有办法处理包括新参数在内的大量参数?例如:

class Thing:
    def __init__(self, arg1, arg2, arg3, arg4):
        # Initialize 

class SubThing(Thing):
    def __init__(self, arg1, arg2, arg3, arg4, ex_arg1, ex_arg2):
        super().__init__(arg1, arg2, arg3, arg4):
        # Do extra initialization 

是否可以缩短子类的__init__ 方法的参数列表? this one 等答案没有描述如何向 init 添加参数,或如何处理额外的关键字参数,例如 __init__(self, arg1, arg_room='Bedroom', ex_arg1, ex_position=(0, 0), ex_arg2)

【问题讨论】:

  • 简短回答:不,如果不写出您想要传递的所有参数,就无法做到这一点。
  • 有 *args 和 **kwargs 但我不认为这正是你所要求的。

标签: python python-3.x


【解决方案1】:

没有真正的伟大方式来做你想做的事。一般来说,命名所有参数是主要的方法。

有一些方法可能会有所帮助。一种是将一些参数捆绑到更大的集合中,因此您只需将一项传递给父类,而不是多个。下面是使用可迭代序列来保存arg1-arg4 的样子,但您可能希望使用自定义类来代替(请参阅csv 模块中的Dialect 类以获取以下类型的示例:为其他类型捆绑了几个参数):

def __init__(self, thing_args, ex_arg1, ex_arg2):
    super().__init__(*thing_args)
    # ...

另一种方法是使用*args 和/或**kwargs 接收您要传递的参数。使用定位 *args 相当有限,因为您必须在传递的所有参数之前列出子类中您关心的参数:

def __init__(self, ex_arg1, ex_arg2, *args):
    super().__init__(*args)
    # ...

调用者需要首先列出ex_argsN 参数的值,这可能是不自然的。子类越多,情况就越糟糕。

要求所有内容都作为关键字参数传递可能会更好,因为调用者可以按照最自然的顺序放置关键字参数:

def __init__(self, *, ex_args1, ex_args2, **kwargs):
    super.__init__(self, **kwargs) # passes along the unnamed keyword args
    # ...

这种方法的最大缺点是所有参数名称的调用变得相当冗长:

st = SubThing(arg1="foo", arg2="bar", arg3="baz", arg4="quux",
              ex_arg1=1, ex_arg2=6.02e23)

【讨论】:

    【解决方案2】:

    除了删除特定于您的子类的项目之外,您可以执行与引用的答案类似的操作。

    class Thing:
        def __init__(self, arg1, arg2, arg3, arg4, kw1=None, kw2=None):
            print('Thing args:',arg1,arg2,arg3,arg4)
            print('Thing kw:',kw1,kw2)
    
    class SubThing(Thing):
        def __init__(self, *args, **kw):
            """SubThing(arg1, arg2, arg3, arg4, arg5, arg6, kw1=None, kw2=None,
            kw3=None, kw4=None)
            """
            if len(args) != 6:
                raise TypeError(
                    "SubThing() takes 6 positional arguments but {} were given"
                    .format(len(args)))
            arg5, arg6 = args[4:]
            kw3 = kw.pop('kw3', None)
            kw4 = kw.pop('kw4', None)
            super().__init__(*args[:4], **kw)
    
    
    SubThing(1,2,3,4,5,6,kw1='kw1',kw4='kw4')
    print('---- but populating kwargs from positional args stops working ----')
    Thing(1,2,3,4, 'kw1', 'kw2')
    SubThing(1,2,3,4,5,6,'kw1','kw2')
    

    这会导致

    Thing args: 1 2 3 4
    Thing kw: kw1 None
    ---- but populating kwargs from positional args stops working ----
    Thing args: 1 2 3 4
    Thing kw: kw1 kw2
    Traceback (most recent call last):
      File "n.py", line 24, in <module>
        SubThing(1,2,3,4,5,6,'kw1','kw2')
      File "n.py", line 14, in __init__
        .format(len(args)))
    TypeError: SubThing() takes 6 positional arguments but 8 were given
    

    请注意,在第二个示例中,您丢失了一些功能,因为额外的位置参数没有自动填充关键字参数。您可以通过更多编码来解决这个问题,或者只是接受限制。许多使用*args, **kw 的课程忘记了这样做,所以你是一个很好的伙伴。

    【讨论】:

      猜你喜欢
      • 2010-11-14
      • 1970-01-01
      • 1970-01-01
      • 2013-06-14
      • 2011-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      相关资源
      最近更新 更多