Как работает проверка if с булевым значением и почему важно различать True и число в Python
Что проверяют
Знаете ли вы, как Python вычисляет истинность и что bool это подкласс int. Следом обычно дают код с if value:, где ноль допустимое значение, и просят найти баг.
Как отвечать
- истинность:
if x:вызываетbool(x), тот ищет__bool__, затем__len__, а если нет ни того ни другого, объект считается истинным. ЛожныNone,False, ноль любого числового типа (0,0.0,0j,Decimal(0)) и пустые коллекции:'',[],{},set(),range(0); boolэтоint:True == 1,True + True == 2,isinstance(True, int)возвращаетTrue. Отсюда{1: 'a', True: 'b'}превращается в{1: 'b'}: уTrueи1одинаковые хеш и равенство, это один ключ;- истинность и равенство разные вещи:
'',[]иNoneложны, но'' == FalseиNone == FalseдаютFalse. РавныFalseтолько нули числовых типов; - идентичность:
True is 1ложно, это разные объекты, а на сравнение с литералом черезisинтерпретатор выдаётSyntaxWarning.
Практическое правило: if x: пишите, когда важно «есть что-то или пусто». Если ноль, пустая строка и None означают разное, проверяйте явно: if x is not None:, if count == 0:. Сравнивать флаг с True через == или is PEP 8 не советует, достаточно if flag:.
Для валидации входных данных помните, что isinstance(value, int) пропустит True. Если булево значение в числовом поле это ошибка, проверяйте isinstance(value, bool) первым или пишите type(value) is int. Полезная сторона того же факта: sum(x > 0 for x in items) честно считает количество.
Где спотыкаются
Пишут if user.age: или if price:, и возраст 0 или бесплатный товар уходят в ветку «не задано». Классика для полей из JSON и аргументов со значением по умолчанию.
Пишут if df: для DataFrame или if arr: для массива NumPy из нескольких элементов и получают ValueError про неоднозначную истинность. Нужны df.empty, arr.size, .any() или .all(), смотря что вы хотели проверить.
Считают, что True и 1 в словаре или множестве будут разными элементами. {True, 1, 1.0} содержит один элемент, и данные молча перезаписываются.