На этом занятии
мы поговорим о способах настройки и определения правдивости объектов классов. Что
такое правдивость? Это когда к экземпляру явно или неявно применяется функция bool(). С ней мы с
вами уже знакомы и применяли к обычным типам данных:
bool(123)
bool(-1)
bool(0)
bool("python")
bool("")
bool([])
В стандартном
поведении она возвращает True для непустых объектов и False – для пустых. Давайте
посмотрим, что она будет выдавать для экземпляров классов. Я возьму класс из
предыдущего занятия:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
Создадим его
объект:
и применим к
нему функцию bool():
Увидим значение True. В
действительности, эта функция всегда возвращает True для любых
объектов пользовательского класса. Получается, что смысла в ней особого нет,
применительно к экземплярам наших классов? Не совсем. Мы можем переопределить
ее поведение либо через магический метод __len__(), либо через
метод __bool__():
- __len__() – вызывается
функцией bool(), если не
определен магический метод __bool__();
- __bool__() – вызывается
в приоритетном порядке функцией bool().
Вначале я
пропишу магический метод __len__() в классе Point, следующим
образом:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __len__(self):
print("__len__")
return self.x * self.x + self.y * self.y
В этом методе я
вычисляю и возвращаю квадрат длины радиус-вектора с координатами (x; y). Запустим
программу и видим значение True, а также сообщение «__len__». То есть,
действительно был вызван метод __len__() и, так как он вернул не нулевое
значение, то функция bool() интерпретировала его как True.
Давайте в
экземпляре класса пропишем нулевые координаты, чтобы длина вектора была
нулевой:
Теперь видим
ожидаемое значение False.
Конечно, если
нам нужно явно описать алгоритм работы функции bool() применительно
к нашим экземплярам класса, то следует использовать магический метод __bool__(). Я запишу
его в таком виде:
def __bool__(self):
print("__bool__")
return self.x == self.y
Теперь, объект
будет считаться правдивым (истинным), если его координаты равны. Запускаем программу
и видим, что для нулей отображается значение True. Если же
прописать не равные координаты:
то получаем
значение False. Конечно, такая
реализация магического метода __bool__() – это лишь учебный пример, чтобы вы
поняли принцип его работы. В реальности, мы можем в этом методе прописывать
любую логику. Единственное условие, чтобы данный метод возвращал булево
значение True или False. Указывать в
операторе return другие типы
данных запрещено.
Все это хорошо,
но где это используется? Чаще всего в условных конструкциях. Например, если
прописать вот такое условие:
if p:
print("объект p дает True")
else:
print("объект p дает False")
Здесь происходит
неявный вызов функции bool() при проверке условия. Поэтому в
программах, где требуется описать собственные проверки истинности или ложности
объектов, то пользуются или магическим методом __len__(), но чаще
всего, магическим методом __bool__().