Функция issubclass(). Наследование от встроенных типов и от object
Мы продолжаем изучение важной темы в ООП – наследование. Вначале нашего курса по ООП я говорил, что пользовательский класс по умолчанию автоматически наследуется от базового класса object языка Python. Например, если записать некий класс Geom без какой-либо реализации:
то, смотрите, в среде PyCharm записав ниже «Geom.» мы увидим список различных методов и свойств. Например, можно вывести значение свойства __class__:
Откуда все это взялось? Как вы уже догадались, от базового класса object, который неявно добавляется, начиная с версии языка Python 3. Это эквивалентно такой записи:
И все эти атрибуты находятся в классе object.
Зачем это было сделано? Очевидно, чтобы обеспечить стандартный базовый функционал работы с классами. В частности, когда мы создаем экземпляр класса:
а, затем, выводим его с помощью функции print:
то автоматически отрабатывает магический метод __str__, который определен в базовом классе object. И так со всеми атрибутами, ничего лишнего там нет. Как вы понимаете, иметь такой базовый функционал очень удобно, поэтому в Python происходит такое наследование по умолчанию от object. В результате, мы имеем иерархию наследования:
Однако, если добавить дочерний класс от Geom, например, класс Line для представления линии:
class Geom(object): pass class Line(Geom): pass
то иерархия наследования уже будет такой:
То есть, указывая в качестве базового любой другой класс, непосредственное наследование от object уже не происходит, только косвенное – через базовые классы. Разумеется, здесь объекты Line также имеют полный доступ ко всем открытым атрибутам класса object:
Мало того, мы можем определять, является ли тот или иной класс подклассом другого класса. Это делает функция issubclass(), например:
Она возвращает значение True, если класс Line является подклассом класса Geom. А вот если указать их в другом порядке:
то получим False, так как класс Geom не является дочерним от класса Line.
А вот с объектами классов эта функция не работает. Если записать:
то получим ошибку, что аргумент должен быть классом, а не его экземпляром. Если нам все же нужно проверить принадлежность объекта тому или иному классу, в том числе и базовому, то следует использовать уже знакомую нам функцию isinstance():
print(isinstance(l, Geom)) print(isinstance(l, Line))
В обоих случаях получим значение True. Также истину вернет и проверка на базовый класс object:
Это еще раз показывает, что все классы неявно наследуются от object.
Наследование от встроенных типов данных
Интересный факт языка Python, что все стандартные типы данных являются классами:
Мы в этом легко можем убедиться, если выполним для них функцию issubclass():
issubclass(int, object) issubclass(list, object)
Всюду увидим True. А мы знаем, что эта функция работает исключительно с классами, а не объектами, поэтому данный факт подтверждает, что эти типы являются классами языка Python.
Раз это так, то что нам мешает наследоваться от них и расширять функционал по мере необходимости? Ничего, поэтому можно сделать, например, такую реализацию:
class Vector(list): def __str__(self): return " ".join(map(str, self)) v = Vector([1, 2, 3]) print(v)
Мы здесь переопределили магический метод __str__ для вывода списка в виде набора данных через пробел. Мало того, теперь тип данных нашего списка стал не list, а Vector:
Конечно, стандартные типы данных редко расширяют с помощью пользовательских классов, но понимать, что они представляют собой классы и что такая возможность в принципе существует, важно.
Итак, из этого занятия вы должны были узнать, что все классы по умолчанию наследуются от базового класса object, как работает функция issubclass() и что из себя представляют встроенные типы данных языка Python.
Видео по теме
Концепция ООП простыми словами
#1. Классы и объекты. Атрибуты классов и объектов
#2. Методы классов. Параметр self
#3. Инициализатор __init__ и финализатор __del__
#4. Магический метод __new__. Пример паттерна Singleton
#5. Методы класса (classmethod) и статические методы (staticmethod)
#6. Режимы доступа public, private, protected. Сеттеры и геттеры
#7. Магические методы __setattr__, __getattribute__, __getattr__ и __delattr__
#9. Свойства property. Декоратор @property
#10. Пример использования объектов property
#11. Дескрипторы (data descriptor и non-data descriptor)
#12. Магический метод __call__. Функторы и классы-декораторы
#13. Магические методы __str__, __repr__, __len__, __abs__
#14 Магические методы __add__, __sub__, __mul__, __truediv__
#15. Методы сравнений __eq__, __ne__, __lt__, __gt__ и другие
#16. Магические методы __eq__ и __hash__
#17. Магический метод __bool__ определения правдивости объектов
#18. Магические методы __getitem__, __setitem__ и __delitem__
#19. Магические методы __iter__ и __next__
#20. Наследование в объектно-ориентированном программировании
#21. Функция issubclass(). Наследование от встроенных типов и от object
#22. Наследование. Функция super() и делегирование
#23. Наследование. Атрибуты private и protected
#24. Полиморфизм и абстрактные методы
#25. Множественное наследование
#27. Как работает __slots__ с property и при наследовании
#28. Введение в обработку исключений. Блоки try / except
#29. Обработка исключений. Блоки finally и else
#30. Распространение исключений (propagation exceptions)
#31. Инструкция raise и пользовательские исключения
#32. Менеджеры контекстов. Оператор with
#34. Метаклассы. Объект type
#35. Пользовательские метаклассы. Параметр metaclass
#36. Метаклассы в API ORM Django
#37. Введение в Python Data Classes (часть 1)
#38. Введение в Python Data Classes (часть 2)
#39. Python Data Classes при наследовании
© 2023 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта