Понимание супер в Python - PullRequest
       19

Понимание супер в Python

3 голосов
/ 27 апреля 2020

Не могли бы вы объяснить мне, как написать смертельный алмаз в Python? Я видел много примеров подобного кода без использования аргументов конструктора, но как только я начинаю использовать аргументы, все становится грязным ...

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

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

class C(A):
    def __init__(self, a, c):
        self.c = c
        super().__init__(a)

class D(B, C):
    def __init__(self, a, b, c, d):
        self.d = d
        # How do I pass a and b to B.__init__
        # and a and c to C.__init__
        # using super() ?
        super().__init__(a, b, c) #???

d = D(1, 2, 3, 4)

Ответы [ 2 ]

1 голос
/ 27 апреля 2020

Самый простой способ, вероятно, состоит в том, что каждый подкласс принимает диктовку kwargs и передает ее на верхний уровень:

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

class B(A):
    def __init__(self, b, **kwargs):
        self.b = b
        super().__init__(**kwargs)

class C(A):
    def __init__(self, c, **kwargs):
        self.c = c
        super().__init__(**kwargs)

class D(B, C):
    def __init__(self, d, **kwargs):
        self.d = d
        super().__init__(**kwargs)

d = D(a=1, b=2, c=3, d=4)

print(d.a, d.b, d.c, d.d)
# 1 2 3 4

При каждом вызове __init__ получает требуемый аргумент и передает остальные в родительский класс. Единственным недостатком является то, что вы должны передавать аргументы в качестве ключевых слов.

0 голосов
/ 27 апреля 2020

Инициализаторы подклассов не имеют совместимых подписей, что является ключом для правильных совместных супер-вызовов.

Простое решение здесь - сделать эти сигнатуры совместимыми - канонически, добавив поддержку varargs и произвольных аргументов ключевых слов по всей цепочке, ie:

# NB: Python3 required, won't work in Py2

class A:
    def __init__(self, a, *args, **kwargs):
        self.a = a

class B(A):
    def __init__(self, a, b, *args, **kwargs):
        super().__init__(a, *args, **kwargs)
        self.b = b

class C(A):
    def __init__(self, a, c, *args, **kwargs):
        super().__init__(a, *args, **kwargs)
        self.c = c

class D(B, C):
    def __init__(self, a, b, c, d, *args, **kwargs):
        super().__init__(a, b=b, c=c, *args, **kwargs)
        self.d = d


d = D(1, 2, 3, 4)

Это, конечно, не решить каждую возможную проблему с множественным наследованием и совместными вызовами super, но MI является хитрым, и есть ограничения на то, что возможно в любом случае.

...