Цепочка наследования с необязательным параметром - PullRequest
0 голосов
/ 05 января 2019

Я хотел, чтобы цепочка наследования имела необязательный параметр. Большинству классов в цепочке необходимо, чтобы параметр становился членом иногда , но я также хочу использовать цепочку в других случаях, чтобы параметр не стал членом .

Я думал о том, чтобы сделать параметр необязательным классом и использовать импорт, но я хочу избежать использования синтаксиса класса для члена optional. А также потому, что все классы в цепочке используются в словаре в качестве ключей.

Альтернативы этому? Я делаю что-то неправильно? Есть ли более питонский путь?

class Top:

    def __init__(self, optional=None):

        if optional is not None:
            self.optional = optional
        return


class Middle(Top):

    def __init__(self, one, optional=None):

        if optional is not None:
            super().__init__(optional)

            self.one = one


class Bottom(Middle):

    def __init__(self, one, two, optional=None):

        if optional is not None:
            super().__init__(one, optional)
        else:
            super().__init__(one)

            self.two = two


a = Middle('one')
b = Middle('one', 'two')
c = Bottom('one', 'two')
d = Bottom('one', 'two', 'three')

Ответы [ 2 ]

0 голосов
/ 05 января 2019

Все, что вам нужно, это иметь оператор if в классе Top (родительский / базовый):

class Top:
    def __init__(self, optional=None):
        if optional is not None:
            self.optional = optional

# (you don’t need an explicit return in __init__)

class Middle(Top): 
    def __init__(self, one, optional=None):
        super().__init__(optional)
        self.one = one

# this applies to Bottom class as well

Теперь не имеет значения, предоставляете ли вы эту опцию или нет. Допустим, вы вызываете Middle без опциональных атрибутов, атрибут one устанавливается так, как ожидается, и Top.__init__ вызывается с None, потому что параметр по умолчанию в Middle устанавливает его на это, если он не предоставлен. Так как ваш параметр по умолчанию None во всех классах, наличие (или отсутствие присутствия) необязательного по существу выполняется.

Лично я даже не включил бы выражение if. Я бы установил атрибут как None, чтобы позже в вашем коде, если вы пытаетесь получить доступ к obj.optional, AttributeError не вызывалось. Я считаю, что следует поддерживать атрибуты согласованными через подклассы, если они наследуются, чтобы любой, кто пытается использовать подклассы, ожидал, что все параметры, используемые в __init__, будут использованы или установлены в качестве атрибутов через многочисленные super() вызовы цепочки наследования и не будут потеряны ,

0 голосов
/ 05 января 2019

Top уже знает, как бороться с optional=None; просто передайте аргумент как есть. Однако имейте в виду, что каждый класс должен быть готов к приему и передаче неизвестных аргументов, в случае, если класс, который вы не определили, наследует от любого из них и добавляет свои собственные аргументы к __init__. (Рассмотрим класс X, который наследуется как от Top, так и от некоторого другого класса Foo, и Foo ожидает, что аргумент ключевого слова bar: X(1, 2, 3, bar=5) в конечном итоге вызовет Top.__init__ без удаления bar пока что. Аргументы ключевого слова - очень хорошая идея при использовании __init__ с super.)

class Top:

    def __init__(self, optional=None, **kwargs):
        super().__init__(**kwargs)
        if optional is not None:
            self.optional = optional


class Middle(Top):

    def __init__(self, one, optional=None, **kwargs):
        super().__init__(optional, **kwargs)
        self.one = one


class Bottom(Middle):

    def __init__(self, one, two, optional=None, **kwargs):
        super().__init__(one, optional, **kwargs)    
        self.two = two
...