Рубрики
Без рубрики

Порядок разрешения метода Python (MRO)

Сегодня мы собираемся посмотреть порядок разрешения метода Python или MRO для краткости. Если вы следуете за руководствами по классам Python и наследования, и вы практиковались в коде, вы поймете, что после того, как иерархия классов перемещается в несколько наследований, вы можете вернуть странные результаты или в конечном итоге с непонятными ошибками. … Подробнее … Подробнее … Python Method порядок (MRO) Подробнее »

Автор оригинала: David Yeoman.

Сегодня мы собираемся посмотреть на Python Разрешение метода Заказать или MRO коротко. Если вы следуете за учебниками на Классы Python и Наследование , и вы практиковались в коде, вы поймете, что после того, как иерархия классов перемещается в несколько наследований, вы можете вернуть странные результаты или в конечном итоге с непонятными ошибками. Но, с другой стороны, если вы понимаете порядок поиска Python, поскольку он поднимается на семейное дерево, ваша кодировка становится легче.

Прочитайте эти статьи, если вам нужен переподготовка на классы Python и наследство. Не стесняйтесь следить за этим видео, как вы снимаете в статье:

Что такое разрешение метода Python (MRO)?

Когда мы называем атрибут или метод в классе с несколькими наследованиями, Python следует конкретному порядку при поиске элемента, который мы ищем. Этот заказ называется порядок разрешения метода, и он соответствует двум правилам:

  1. Дети предшествуют своим родителям в процессе сортировки
  2. Когда детский класс наследует Из нескольких классов родительских и дедушек порядок поиска следует за заказ, указанным в __Bases__ атрибут Отказ

Чтобы понять эти правила, у нас есть три концепции для изучения. __Bases__ атрибут, __mro__ атрибут, а Python встроенный супер класс «Объект».

Одна будьте здесь, есть два метода MRO в зависимости от версии Python, которую вы используете. Хотя разница между ними вряд ли порадует большинство из нас в повседневном использовании, я предполагаю, что если вы изучаете Python сегодня, вы используете версию 3.x, и по этой причине я поговорим с новым стилем классов в этой статье.

Что такое атрибут __bases__?

__Bases__ Атрибут – это встроенный класс Python, который выводят базовые классы любого Класс Вы называете это.

Давайте назовем __Bases__ Атрибут на примере нескольких наследований, чтобы увидеть вывод. Вот блок-схема того, что код будет отображаться. Два класса дедушек, протекающие в родительский класс, который затем проходит в детский класс.

И код здесь. Складские и складские классы – дедушка, класс продукции является родительским, а плоды – это ребенок.

class stock():  # Grandparent
    pass

class warehouse():  # Grandparent
    pass

class produce(stock, warehouse):  # Parent
    pass

class fruit(produce):  # Child
    pass

print(fruit.__bases__)

print(produce.__bases__)

# Result

(,)
(, )

Обратите внимание, что __Bases__ Звоните на фруктовые шоу продукты как Родитель Отказ Призыв __Bases__ на производить Класс возвращает сток и Склад как его Родитель Отказ Как указано в двух правилах ранее, сток и Склад Следовательно, порядок поиска, который будет следовать Python при поиске дерева.

Представляем атрибут __mro__

Этот атрибут только для чтения в Python, когда вызывается, возвращает кортеж Из классов, которые рассматриваются Python при поиске базовых классов во время разрешения метода. Давайте назовем __mro__ на сток Класс, который мы использовали в последнем примере, чтобы увидеть, что возвращает.

class stock():
    pass

print(stock.__mro__)

# Result

(, )

Обратите внимание, что в кортеже есть два предмета. Первый – это сток Класс, как вы ожидаете, как это нынешний класс. Но что упоминается класс объекта? сток Класс – это родительский класс и у него нет своих родителей, не так ли?

Python Base Object Object Class

Python имеет встроенный супер класс под названием объект , который является родительским классом для всех новых классов, которые явно не наследуют из других мест. Например, наш фондовый класс в предыдущем коде не имел никакого наследования, указанного в скобках, поэтому он наследует из встроенного Super класса Python, называемый объект Отказ Поэтому, когда мы просим Python к Печать Разрешение метода Заказать или mrro для любого класса, вы увидите, что последний класс возвращен будет объект Отказ

Использование __mro__, чтобы увидеть порядок разрешения метода

Если мы вернемся в наш полный код, мы позвоним __mro__ Атрибут на дочернем классе, Фрукты и посмотрите, что возвращено.

class stock():  # Grandparent
    pass

class warehouse():  # Grandparent
    pass

class produce(stock, warehouse):  # Parent
    pass

class fruit(produce):  # Child
    pass

print(fruit.__mro__)

# Result

(, , , , )

Поскольку вы ожидаете от нашего предыдущего обсуждения, мы возвращаем разрешение метода для нашей гибридной структуры наследования. Возвращение кортеж следует за порядком двух __Bases__ Возвращает мы получили ранее; Это показывает заказ, начиная с текущего класса Фрукты Тогда производить , сток , Склад , и, наконец, супер класс ‘ объект ‘.

Более сложные структуры

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

Тогда вот код, представленный этой блок-схемой.

class stock(): # Grandparent
    pass

class warehouse(stock):  # Parent 1
    pass

class supplier(stock):  # Parent 2
    pass

class canned(warehouse, supplier):  # Child
    pass

print(canned.__mro__)

# Result

(, , , , )

Так что это интересно. Заказ следовал не то, что вы можете ожидать. Конечно, было бы более эффективно искать одну руку алмаза, из консервированного, на склад, затем на складе, прежде чем вернуться к поиску правой стороны через поставщик снова на складе?

Однако Python не может работать с двусмысленностью, и если бы искать, как описано, вы получите следующий заказ:

canned > warehouse > stock > object > supplier > stock > object

Это просто не работает, потому что при работе с наследством вопросов приоритета. Это означает, что у вас не может быть класс дедушка, например сток перед родительским классом, таким как поставщик. Или объект супер класса, впереди бабушка и родителя. Вот почему порядок разрешения метода определяется как:

canned > warehouse > supplier > stock > object

Этот маршрут соответствует те двум правилам, которые мы ввели в начале этой статьи.

  1. Дети предшествуют своим родителям в процессе сортировки
  2. Когда детский класс наследует от нескольких родительских и дедушек классов, порядок поиска следует за заказ, указанным в __Bases__ атрибут.

Почему MRO имеет значение?

Как только ваш код начнет становиться более сложным, с несколькими уровнями наследования, гибридных структур и вложенных классов, жизнь начинает становиться громоздким. Если классы используют один и тот же атрибут или имена методов, вы можете получить неприятный сюрприз при вызове метода или атрибута, только для возврата полностью неожиданного значения. Вы также можете получить сообщение об ошибке, когда Python не может разрешить двусмысленность или конфликт следующим образом.

class supplier():
    level = 1

class distributor():
    level = 1

class shop_warehouse(supplier, distributor):
    level = 2

class shop_dispatch(shop_warehouse):
    level = 3

class shelf(distributor, shop_dispatch):
    pass

print(shelf.level)

# Result

TypeError: Cannot create a consistent method resolution
order (MRO) for bases distributor, shop_dispatch

Почему? Вот блок-схема.

Мы знаем, что более высокий класс не может прийти перед более низким классом, но это то, что мы просим, когда мы создали класс полки, используя полка (дистрибьютор, shop_dispatch) Отказ Есть два решения этой проблемы. Одним из них – это переодеться в скобные классы для чтения Полка (Shop_Dispatch, Дистрибьютор) Как показано здесь. Но вы исправляете за ловушку, которая может возникнуть с дальнейшими изменениями кода, оставив вас с грязным и возможно проблемным кодом.

class supplier():
    level = 1

class distributor():
    level = 2

class shop_warehouse(supplier, distributor):
    level = 4

class shop_dispatch(shop_warehouse):
    level = 5

class shelf(shop_dispatch, distributor):
    pass

print(shelf.level)

# Result

5

Другой метод состоит в том, чтобы удалить класс дистрибьютора в качестве родителя полка Поскольку все атрибуты и методы доступны через иерархию. См. Следующий код, в котором мы сняли ссылку на класс дистрибьютора из полка класс. Чтобы доказать, что это работает, мы затем добавили метод в классе дистрибьютора, созданный объектом, используя полка Класс, затем называется методом метки с использованием нового объекта.

class supplier():
    level = 1

class distributor():
    level = 2
    def label(self):
        print('Distributor label')

class shop_warehouse(supplier, distributor):
    level = 4

class shop_dispatch(shop_warehouse):
    level = 5

class shelf(shop_dispatch):
    pass

a4 = shelf()  # Instantiated an object using class shelf

a4.label()  # Called the method label() which sits within the distributor class

# Result

Distributor label

Тогда, если мы позвоним __mro__ Метод на полка Класс, который мы видим следующее возвращено.

(, , , , , )

Хороший, аккуратный и понятный код с четко определенным порядком разрешения метода.

Резюме

Сегодня мы подчеркнули порядок разрешения метода или MRO, в Python, который является поручением, в котором Python ищет классы, атрибуты и методы при работе с наследством нескольких классов, и мы обсудили важность такого порядка. Три значимых атрибута, называются __Bases__ , __mro__ И объект Super класса Python в построенном Python был рассмотрен и показан в действии. Мы также представили два правила Python при восхождении на семейное дерево, ищущие классы, методы и атрибуты. Наконец, мы показали, где могут возникнуть ошибки при работе с несколькими наследованиями, почему они могут произойти, а как зная, что основы MRO могут помочь нам избежать их. Большое спасибо за чтение, и я доверяю, статью оказала помощь.