Написать пост

Используем объекты вместо True и False — truthy и falsy значения в Python

Рассказываем про ложные и истинные значения, что их делает таковыми и как, используя истинные значения, можно сократить код.

Значения вместо булевых переменных

В Python, как и в других языках, есть логический тип переменных bool, который имеет всего два значения: True (истина) и False (ложь). Его возвращают логические операторы (например сравнение чисел или проверка присутствия элемента в списке), и именно этот тип обычно используется в if и while. Тем не менее, явно использовать bool или операторы необязательно: существуют правила, по которым значение любого типа приводится к True или False.

Прим  пер.По-английски это называется truthy и falsy, то есть «примерно-но-не-совсем-истинные», «истинноватые» значения. Общепринятого русского перевода нет, но в этой статье под истинным или ложным значением объекта всегда подразумеваются именно эти штуки, а булевы значения везде названы True и False.

Вот как это работает:

			>>> a = 5

>>> if a:
    print(a)
# Вывод
5

>>> a = 0

>>> if a:
    print(a)

# Ничего не выводится
		

Булев контекст

Любое значение в Python при необходимости может интерпретироваться как True или False в соответствии с правилами языка. Об этом написано и в документации:

Любой объект может быть протестирован на истинность и использован в условиях if и while, а также как операнд булевых операций (and, or, not).

Если объект используется таким образом, то он находится в булевом контексте. Грубо говоря, это такое место в коде, которое требует от объекта значения либо True, либо False.

В булевом контексте может использоваться как переменная, так и выражение. Если используется выражение, значит, оценивается истинность его результата.

Объекты, которые приравниваются к False

Любой объект, для которого определен метод  __len__ , возвращающий для этого объекта 0, является falsy. Документация:

По умолчанию объект считается истинным, если его класс не определяет метод __bool__, возвращающий для объекта False, или метод __len__, возвращающий для него ноль.

Последовательности и коллекции

  • пустой список: [];
  • пустой кортеж: ();
  • пустой словарь: {};
  • пустое множество: set();
  • пустая строка: «»;
  • пустой диапазон: range(0).

Нули любых численных типов

  • целочисленный ноль: 0;
  • ноль с плавающей точкой: 0.0;
  • комплексный ноль: 0j.

Константы

  • None;
  • False.

Объекты, которые приравниваются к True

Согласно документацииПо умолчанию любой объект имеет истинное значение.

В частности, истинными являются:

  • все непустые последовательности и коллекции (списки, кортежи, словари, множества, диапазоны и строки);
  • все ненулевые числа;
  • True.

Функция bool()

С помощью этой функции можно проверить истинность или ложность любого значения. Согласно документации, она:

Возвращает булево значение, т. е. либо True, либо False. Аргумент x конвертируется с использованием стандартной процедуры проверки истинности.

Например:

			>> bool(5)
True
>>> bool(0)
False
		

Передавать этой функции можно как значение, так и содержащую его переменную.

Зачем это нужно?

Преимущество истинных и ложных значений в том, что они позволяют сделать код кратким и понятным. Вот два примера:

Пример 1, с сообщением об ошибке:

Допустим, у нас есть функция print_even(), которая принимает в качестве аргумента список или кортеж чисел и печатает его чётные элементы. Если список пустой, то выводится сообщение:

			def print_even(data):
  if len(data) > 0:
    for value in data:
      if value % 2 == 0:
        print(value)
   else:
     print("Пустой список в аргументе")
		

Обратите внимание на эту строчку:

			if len(data) > 0:

		

Её можно сократить до:

			if data:

		

Если список пустой, data имеет ложное значение. Если он не пустой (то есть его длина больше нуля), то истинное. Тот же результат достигается меньшим количеством кода:

			def print_even(data):
  if data:
    for value in data:
      if value % 2 == 0:
        print(value)
   else:
     print("Пустой список в аргументе")
		

Пример 2, с исключением:

Можно использовать истинные/ложные значения, чтобы выбросить исключение, если аргумент некорректен.

			>>> def print_even(data):

  if not data:
    raise ValueError("The argument data cannot be empty")

  for value in data:
    if value % 2 == 0:
      print(value)
		

Если список data пустой:

  • data имеет ложное значение, эквивалентное False;
  • поэтому not data эквивалентно not False, то есть True;
  • поэтому условие if истинно;
  • поэтому бросается исключение.

Если список не пустой:

  • data имеет истинное значение, эквивалентное True;
  • поэтому not data эквивалентно not True, то есть False;
  • поэтому условие if ложно;
  • поэтому исключение не бросается.

Истинные и ложные значения произвольных объектов

Если вы хотите, чтобы у ваших объектов были не только истинные значения, можно добавить к классу метод __bool__() и задать в нём правила, по которым будет определяться истинность или ложность объекта.

Например, у нас есть вот такой класс:

			>>> class Account:

  def __init__(self, balance):
    self.balance = balance
		

Поскольку у него нет специальных методов, все объекты этого класса имеют истинное значение:

			>>> account1 = Account(500)
>>> bool(account1)
True
>>> account2 = Account(0)
>>> bool(account2)
True
		

Это можно исправить, добавив __bool__():

			>>> class Account:
  def __init__(self, balance):
    self.balance = balance

  def __bool__(self):
    return self.balance > 0
		

Теперь объект имеет истинное значение, пока на счету больше нуля. При нулевом или отрицательном балансе значение будет ложным.

			>>> account1 = Account(500)
>>> bool(account1)
True
>>> account2 = Account(0)
>>> bool(account2)
False
		

Если у класса нет метода __bool__(), но есть метод __len__(), то истинность объекта определяется истинностью того, что возвращает __len__().

Вот так работает механизм, позволяющий использовать любые объекты в качестве булевых. С его помощью можно сделать код проще и понятнее; важно только не забывать осмысленно называть переменные — какое-нибудь 

			pabotat() if cnucok_2 else He_pabotat()
		

 никуда не годится что с булевским контекстом, что без него.

Адаптированный перевод «Truthy and Falsy Values in Python: A Detailed Introduction»

Автор перевода Алексей Морозов

Следите за новыми постами
Следите за новыми постами по любимым темам
68К открытий69К показов