Питон - статьи

         

Тестирование родословной


>
>
>
issubclass(D,C) True >
>
>
issubclass(D,A) True >
>
>
issubclass(A,B) False >
>
>
issubclass(d,D) [...] TypeError: issubclass() arg 1 must be a class

А теперь интересный вопрос, необходимый для понимания различия между базовыми классами и метаклассами: как разрешается атрибут наподобие d.attr. Для простоты, рассмотрим только стандартное правило просмотра, а не "сваливание" в .__getattr__(). Первый шаг в таком разрешении - поискать в d.__dict__ имя attr. Если оно найдено - это все; но если нет, должно произойти что-то фантастическое, как, например:

>
>
>
d.__dict__, d.a5, d.a1

({'a5': 'instance d'}, 'instance d', 'A')

Хитрость, позволяющая найти атрибут, который не прикреплен к экземпляру - поискать его в классе экземпляра, а после этого во всех базовых классах. Порядок, в котором просматриваются производные классы, называется порядком разрешения метода (method resolution order) для этого класса. Вы можете увидеть его с помощью (мета)метода .mro() (но только из объектов класса):

>
>
>
[k.__name__ for k in d.__class__.mro()]

['D', 'C', 'A', 'B', 'object']

Другими словами, обращение к d.attr сначала ищет в d.__dict__, а затем в D.__dict__, C.__dict__, A.__dict__, B.__dict__ и в конце в object.__dict__. Если имя не найдено ни в одном из этих мест, возбуждается исключение AttributeError.

Заметьте, что в этой процедуре поиска метаклассы не были упомянуты ни разу.



Содержание раздела