Избегайте указания всех аргументов в подклассе - PullRequest
19 голосов
/ 07 февраля 2010

У меня есть класс:

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

И у меня есть подкласс, которому нужен один дополнительный аргумент (последний 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

Кажется глупым писать весь этот код, например, передавать все аргументы из Ctor B во внутренний вызов ctor A, с тех пор каждое изменение в A ctor должен применяться к двум другим местам в коде B.

Я предполагаю, что у python есть некоторая идиома для обработки таких случаев, о которых я не знаю. Можете ли вы указать мне правильное направление?

Моя лучшая догадка, это иметь своего рода Copy-Ctor для A, а затем изменить код B на

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

Это соответствовало бы моим потребностям, так как я всегда создаю подкласс, когда предоставляется экземпляр класса отца, хотя я не уверен, возможно ли это ...

Ответы [ 4 ]

20 голосов
/ 07 февраля 2010

Учитывая, что аргументы могут передаваться либо по имени, либо по позиции, я бы написал:

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
7 голосов
/ 07 февраля 2010

Редактировать: на основе предложения Мэтта и для решения проблемы Гнибблера с помощью подхода с позиционным аргументом; вы можете проверить, чтобы убедиться, что указан дополнительный специфичный для подкласса аргумент - аналогично ответ Алекса :

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

Оригинальный ответ:
Та же идея, что и у ответа Мэтта , вместо этого используется 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 голосов
/ 13 июня 2016

В ситуациях, когда некоторые или все аргументы, переданные в __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
0 голосов
/ 07 февраля 2010

Вы хотите что-то подобное?

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