Avoid specifying all arguments in a subclass

岁酱吖の 提交于 2019-11-27 01:50:26

问题


I have a class:

class A(object):
    def __init__(self,a,b,c,d,e,f,g,...........,x,y,z)
        #do some init stuff

And I have a subclass which needs one extra arg (the last W)

class B(A):
    def __init__(self.a,b,c,d,e,f,g,...........,x,y,z,W)
        A.__init__(self,a,b,c,d,e,f,g,...........,x,y,z)
        self.__W=W

It seems dumb to write all this boiler-plate code, e.g passing all the args from B's Ctor to the inside call to A's ctor, since then every change to A's ctor must be applied to two other places in B's code.

I am guessing python has some idiom to handle such cases which I am unaware of. Can you point me in the right direction?

My best hunch, is to have a sort of Copy-Ctor for A and then change B's code into

class B(A):
     def __init__(self,instanceOfA,W):
         A.__copy_ctor__(self,instanceOfA)
         self.__W=W

This would suit my needs since I always create the subclass when given an instance of the father class, Though I am not sure whether it's possible...


回答1:


Considering that arguments could be passed either by name or by position, I'd code:

class B(A):
    def __init__(self, *a, **k):
      if 'W' in k:
        w = k.pop('W')
      else:
        w = a.pop()
      A.__init__(self, *a, **k)
      self._W = w



回答2:


Edit: based on Matt's suggestion, and to address gnibbler's concern re a positional-argument approach; you might check to make sure that the additional subclass-specific argument is being specified—similar to Alex's answer:

class B(A):
  def __init__(self, *args, **kwargs):
    try:
      self._w = kwargs.pop('w')
    except KeyError:
      pass
    super(B,self).__init__(*args, **kwargs)

>>> b = B(1,2,w=3)
>>> b.a
1
>>> b.b
2
>>> b._w
3

Original answer:
Same idea as Matt's answer, using super() instead.

Use super() to call superclass's __init__() method, then continue initialising the subclass:

class A(object):
  def __init__(self, a, b):
    self.a = a
    self.b = b

class B(A):
  def __init__(self, w, *args):
    super(B,self).__init__(*args)
    self.w = w



回答3:


In situations where some or all of the arguments passed to __init__ have default values, it can be useful to avoid repeating the __init__ method signature in subclasses.

In these cases, __init__ can pass any extra arguments to another method, which subclasses can override:

class A(object):
    def __init__(self, a=1, b=2, c=3, d=4, *args, **kwargs):
        self.a = a
        self.b = b
        # …
        self._init_extra(*args, **kwargs)

    def _init_extra(self):
        """
        Subclasses can override this method to support extra
        __init__ arguments.
        """

        pass


class B(A):
    def _init_extra(self, w):
        self.w = w



回答4:


Are you wanting something like this?

class A(object):
    def __init__(self, a, b, c, d, e, f, g):
        # do stuff
        print a, d, g

class B(A):
    def __init__(self, *args):
        args = list(args)
        self.__W = args.pop()
        A.__init__(self, *args)


来源:https://stackoverflow.com/questions/2215923/avoid-specifying-all-arguments-in-a-subclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!