Как заставить дочерний класс использовать значения родительского по умолчанию?

#python #python-3.x #inheritance

#python #python-3.x #наследование

Вопрос:

У меня есть родительский класс:

 class BaseClass:
    def __init__(self, foo, bar=10):
        self.foo = foo  
  

И унаследованный от него класс:

 class InheritedClass(BaseClass):
    def __init__(self, x, y, bar=10):
        super().__init__(True, bar=bar)
        self.x = x
        self.y = y
  

На данный момент bar имеет значение по умолчанию как в родительском, так и в унаследованном классе, которое я должен отслеживать, чтобы убедиться, что они оба синхронизированы. Как я могу изменить InheritedClass конструктор, чтобы вместо этого использовать значение по умолчанию для bar определенного в BaseClass ?


Я пробовал:

 class InheritedClass(BaseClass):
    def __init__(self, x, y, bar=None):
        if bar is None:
            super().__init__(True)
        else:
            super().__init__(True,bar)
        self.x = x
        self.y = y
  

который обеспечивает поведение, которое я ищу, но кажется не очень масштабируемым. Есть ли лучший способ?

Ответ №1:

Вообще не указывайте аргументы родительского класса в подписи; просто передайте то, что вы получаете (если что-либо), следующему классу в MRO.

 class BaseClass:
    def __init__(self, foo, bar=10, **kwargs):
        super().__init__(**kwargs)
        # Do something with bar
        self.foo = foo


class InheritedClass(BaseClass):
    def __init__(self, x, y, **kwargs)
        kwargs['foo'] = True
        super().__init__(**kwargs)
        self.x = x
        self.y = y
  

Вы все равно должны принимать и передавать произвольные ключевые слова для super правильного использования, поэтому вы также можете сделать то же самое для аргументов родительского класса, даже если вы их уже «знаете».

Это также означает всегда использовать аргументы ключевого слова для __init__ , поскольку вы не можете предсказать, как позиционные аргументы вашего класса будут взаимодействовать с другим классом в MRO. (Позиционные аргументы могут использоваться только в порядке поступления, и вы просто не знаете, в случае множественного наследования, когда будет вызван метод вашего класса.)

 foo = InheritedClass(bar=9, x=3, y=10)
  

Комментарии:

1. Спасибо за ответ, Чепнер. Очень ясно, за небольшим исключением последнего абзаца. Я не очень знаком с контекстом, который вы описываете. Не могли бы вы рассказать немного больше?

2. Смотрите, Python super() считается супер! , особенно раздел о практических советах.

3. В общем, то, что ваш базовый класс наследует только от object , не означает, что он всегда будет последним классом в MRO какого-то другого класса.

4. Еще раз спасибо, Чепнер.

Ответ №2:

Вместо этого вы можете использовать переменные аргументы:

 class InheritedClass(BaseClass):
    def __init__(self, x, y, *args, **kwargs):
        super().__init__(True, *args, **kwargs)
        self.x = x
        self.y = y
  

Ответ №3:

Ваш подход неплох, и да, есть лучший способ сделать это, возможно, лучше моего, но вот что я придумал, надеюсь, это поможет.

Пример:

 class BaseClass:
    def __init__(self, foo, bar=10):
        self.foo = foo 
        self.bar = bar 

class InheritedClass(BaseClass):
    def __init__(self, x, y, bar=None):
        super().__init__(True, bar=bar)
        if bar is None: bar = self.bar
        self.x = x
        self.y = y