Используя python, если есть алмазная структура, функция super() в левом углу относится к классу в правом углу, а не к верхнему. Почему?

#python #inheritance #diamond-problem

Вопрос:

Я использую (и учусь) Python3 У меня есть высший класс (geometry_0) , определяющий структуру описания геометрии, и его дочерние элементы (геометрия(geometry_0)), которые дают структуру измененной геометрии. Производные классы, например, простая геометрия: парабола(geometry_0) и модифицированный параболо_шифрованный(геометрия,парабола). Геометрия содержит функцию super (), но она ссылается на параболу, а не на geometry_0. Я доволен этим, но не понимаю, почему. Это своего рода структура алмаза, может быть, это может быть позади? Но что происходит во время компиляции?

Упрощенный фиктивный код:

 class Geometry_0():

    @classmethod
    def x2y(cls,geom_pars: dict, x: float) -> float:
        print('in Geometry_0')
        return NotImplemented

class Geometry(Geometry_0):

    @classmethod
    def transform(cls,geom_pars: dict, x_child: float) ->float:

        return NotImplemented

    @classmethod
    def x2y(cls,geom_pars: dict, x_child: float):
        print('in Geometry')
        x_parent = cls.transform(geom_pars,x_child)

        return super().x2y(geom_pars,x_parent) # that should refer to geometry_0 ??

class Parabola(Geometry_0): # y = a * x**2

    @classmethod
    def x2y(cls, geom_pars, x):
        print('in Parabola')
        a = geom_pars['a']
        return a * x**2

class Parabola_shifted(Geometry,Parabola): # y = a * (x-x0)**2

    @ classmethod
    def transform(cls,geom_pars: dict, x_child: float) ->float:
        x0 = geom_pars['x0']
        x_parent = x_child - x0

        return x_parent
    # x2y is inherited from geometry, that calls the super().x2y

print('parabola')
print(Parabola.x2y({'a': 1},2))
print('shifted parabola')
print(Parabola_shifted.x2y({'a':1, 'x0': 2}, 2))
 

На выходе получается:

 parabola at 2: y= 1* 2**2 = 4
in Parabola
4
shifted parabola at 2: y= 1* (2-2)**2 = 0
in Geometry
in Parabola
0
 

Ответ №1:

Вам нужно понять MRO Python (Порядок разрешения методов).

Вот хороший урок: https://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path

Для получения более подробной информации вы можете посмотреть следующее: https://www.python.org/download/releases/2.3/mro/

Пример: D расширяет B и C, сами расширяя A.

 class A:
    def display(self):
        print('A')

class B(A):
    def display(self):
        print('B')
        super().display()

class C(A):
    def display(self):
        print('C')
        super().display()

class D(B, C):
    def display(self):
        print('D')
        super().display()

d = D()
d.display()
 

super будет следовать за MRO и, в зависимости как от контекста класса, в котором он вызывается, так и от типа экземпляра, он найдет следующий объект в списке приоритетов

выход:

 D
B
C
A
 

Алгоритм начинается с объявленного графика наследования и удаляет дублированные записи, сохраняя только их последнее появление

С предыдущим примером:

 D, B, object , C, object ⇒ D, B, C, object
 

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

1. Тогда я прав в следующем?: путь поиска в вашем коде-DBACA. Старый MRO удаляет те же классы, что и раньше, в то время как новый удаляет те же классы, что и раньше, поэтому в python

2. Я думаю, что это DBAC для python

3. Извините, да, DBAC, я просто не могу это исправить