简体   繁体   English

如何扩展大类方法?

[英]How to Extend Large Class Methods?

In the case that you want to extend a class and its respective __init__ method, is there a way to handle a large number of arguments including new ones? 如果要扩展一个类及其相应的__init__方法,是否可以处理包括新参数在内的大量参数? For example: 例如:

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 

Is it possible to shorten the list of arguments for the __init__ method of the subclass? 是否可以缩短子类的__init__方法的参数列表? Answers such as this one don't describe how to add arguments to the init, or how to handle extra keyword arguments such as __init__(self, arg1, arg_room='Bedroom', ex_arg1, ex_position=(0, 0), ex_arg2) . 像这样的回答这一个没有描述如何将参数添加到init,或者如何处理额外的关键字参数,例如__init__(self, arg1, arg_room='Bedroom', ex_arg1, ex_position=(0, 0), ex_arg2)

There isn't really a great way to do what you want. 真正没有一种做您想要的事情的方法。 Generally speaking, naming all the arguments is the main way to go. 一般来说,命名所有参数是主要的方法。

There are a few approaches that might help though. 有一些方法可能会有所帮助。 One is bundling up some of the arguments into larger collections, so you only need to pass one item on to the parent class, rather than several. 一种是将一些参数捆绑到更大的集合中,因此您只需要将一项传递给父类,而不是多项。 Here's what that might look like using an iterable sequence to hold arg1 - arg4 , but you might want to use a custom class instead (see the Dialect class in the csv module for an example of a type that bundles up several arguments for other types): 使用可迭代序列保存arg1 - arg4可能看起来像这样,但您可能想改用自定义类(有关将其他类型的多个参数捆绑在一起的类型的示例,请参阅csv模块中的Dialect类) :

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

The other way to go is to use *args and/or **kwargs to receive the arguments you want to pass along. 另一种方法是使用*args和/或**kwargs接收要传递的参数。 Using positional *args is rather limiting, since you have to list the arguments you care about in the subclass ahead of all the arguments you're passing along: 使用位置*args是相当有限的,因为您必须在传递的所有参数之前列出子类中您关心的参数:

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

Callers will need to list the values for the ex_argsN paramters first, which may be unnatural. ex_argsN者将需要首先列出ex_argsN参数的值,这可能是不自然的。 It gets ever worse the more subclasses there are. 子类越多,情况就越糟。

Requiring everything be passed as keyword arguments may be nicer, since the caller can put the keyword arguments in whatever order seems most natural: 要求将所有参数作为关键字参数传递可能会更好,因为调用方可以按最自然的顺序放置关键字参数:

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

The biggest downside to this approach is that a call gets rather verbose with all the parameter names: 这种方法的最大缺点是,使用所有参数名称的调用变得非常冗长:

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

You can do something similar to the referenced answer except remove the items that are specific to your subclass. 您可以执行与引用的答案类似的操作,除了删除特定于您的子类的项。

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')

This results in 这导致

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

Notice in the second example, you lost some functionality because extra positional arguments didn't automatically fill in keyword arguments. 请注意,在第二个示例中,您失去了一些功能,因为多余的位置参数没有自动填充关键字参数。 You can fix that with more coding or just accept the restrictions. 您可以使用更多编码来解决该问题,也可以接受限制。 Lots of classes that use *args, **kw forget to do that so you are in good company. 许多使用*args, **kw忘记这样做,因此您的关系很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM