При проверке истинности объекта, у класса которого определены bool и len, какой метод Python использует первым?
Python сначала вызывает специальный метод bool. Метод len используется только как запасной вариант, если bool не определён. Поэтому наличие обоих методов делает результат bool определяющим.
Проверка истинности — единый протокол языка для условий, логических операций и встроенной функции bool. Он позволяет объектам описывать естественное понятие «пустой» или «непустой» без привязки к конкретному типу данных.
Исторически этот протокол совместил два распространённых способа трактовки объекта: явное логическое состояние через bool и размер через len. Благодаря этому контейнеры могут считаться ложными при нулевой длине, а другие объекты — задавать собственную семантику.
Разработчик может определить оба метода, ожидая, что Python каким-либо образом объединит их результаты. На самом деле последовательность выбора фиксирована: Python не сравнивает и не комбинирует значения, возвращённые bool и len.
Ошибка в понимании этого порядка приводит к неожиданным результатам в условиях, фильтрации, выражениях and и or. Особенно опасно случайно сделать объект истинным через bool, хотя его длина равна нулю.
При проверке истинности Python ищет специальный метод bool на уровне класса объекта. Если этот метод найден, вызывается именно он, а результат должен быть объектом типа bool. Возвращение произвольного «истинного» объекта вместо True или False приводит к TypeError.
Если bool отсутствует, Python обращается к len. Нулевое значение длины означает ложность, положительное — истинность. Реализация len должна возвращать неотрицательное целое число, иначе проверка может завершиться исключением.
Если отсутствуют оба метода, объект считается истинным по умолчанию. Специальные методы ищутся не в словаре конкретного экземпляра, а в классе и его базовых классах, что соответствует общему правилу поиска большинства протокольных операций Python.
Минимальный пример:
Несмотря на нулевую длину, результат равен True, потому что bool имеет приоритет над len. Если удалить bool, тот же объект станет ложным из-за результата len.
Практический компромисс таков: bool следует определять, когда истинность имеет самостоятельный смысл и не выводится непосредственно из размера. Для контейнеров обычно достаточно len, чтобы избежать дублирования логики. Нельзя использовать len как универсальную замену сложной проверке состояния, если размер и доступность объекта означают разные вещи.
В ORM-обёртке объект запроса может иметь нулевое число уже загруженных записей, но при этом быть корректным и готовым выполнить запрос к базе данных. Если класс определит только len, проверка такого объекта в условии будет ложной, хотя запрос ещё не выполнялся.
Рассматривались два варианта. Можно было оставить только len: это проще и согласуется с семантикой коллекции, но смешивает количество загруженных элементов с состоянием самого запроса. Можно было определить bool, явно возвращающий истинность при валидном и активном запросе: это точнее, но требует документировать, что логическая проверка не означает проверку непустого результата.
Выбран второй вариант, потому что объект моделирует операцию, а не готовый список. В результате условные проверки больше не зависели случайно от промежуточного размера кэша; для проверки наличия результатов использовался отдельный явный метод.
Нет. Результат bool должен быть именно экземпляром bool — обычно True или False. Возврат, например, непустого списка не запускает дополнительное приведение к логическому значению, а приводит к TypeError.
Объект будет ложным. При наличии bool метод len для проверки истинности не используется, поэтому его результат не может переопределить результат bool. Это важное следствие при наследовании: унаследованный или добавленный позже bool может изменить поведение класса, даже если его длина осталась прежней.
Да, обе операции используют тот же протокол истинности: сначала bool, затем len, затем значение «истина» по умолчанию. Различие может быть только в контексте обработки исключения: если протокол завершился ошибкой, условие и bool также не смогут получить результат, если ошибка не перехвачена.