避免在子类中指定所有参数

时间:2010-02-07 04:24:43

标签: python constructor arguments subclass

我有一个班级:

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

我有一个子类需要一个额外的arg(最后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

编写所有这些样板代码似乎很愚蠢,例如将所有args从B的Ctor传递到内部调用A的ctor,从那以后每次更改{{{ 1}}的ctor必须应用于A代码中的其他两个地方。

我猜python有一些习惯用来处理我不知道的这种情况。你能指出我正确的方向吗?

我最好的预感,就是为A创建一种Copy-Ctor,然后将B的代码改为

B

这符合我的需要,因为我总是在给出父类的实例时创建子类,虽然我不确定它是否可能......

4 个答案:

答案 0 :(得分:20)

考虑到参数可以通过名称或位置传递,我会编码:

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

答案 1 :(得分:7)

编辑:基于马特的建议,并解决gnibbler关注的问题,即位置论证方法;您可以检查以确保指定了附加的子类特定参数 - 类似于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

原始答案:
Matt's answer相同,改为使用super()

使用super()调用超类的__init__()方法,然后继续初始化子类:

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

答案 2 :(得分:2)

在传递给__init__的部分或全部参数都有默认值的情况下,避免在子类中重复__init__方法签名会很有用。

在这些情况下,__init__可以将任何额外的参数传递给另一个方法,子类可以覆盖:

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

答案 3 :(得分:0)

你想要这样的东西吗?

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)