Логический тип

В программировании очень многое строится на сравнении и проверке условий. Когда вы нажимаете кнопку выстрела в компьютерной игре, движок игры проверяет остались ли патроны в магазине вашего пистолета, и, если нет, то он запускает анимацию перезарядки. И сколько бы раз вы не пытались нажать кнопку выстрела, до тех пор пока идет анимация, у вас не получится поразить противника. Для хранения результата операции сравнения есть специальный тип данных bool. Есть два значения типа bool: True («Истина») и False («Ложь»). Обратите внимание, что это ключевые слова языка, поэтому пишутся они только с большой буквы.

Логический тип — это базовый тип языка.

В простейшем виде переменные будут выглядеть так:

>>> yes = True
>>> yes
True
>>> no = False
>>> no
False
>>> type(yes)
<class 'bool'>

Базовые свойства

Давайте изучим базовые свойства объектов True и False.

Если попытаться преобразовать сами True или False в числа то получим:

>>> int(True)
1
>>> int(False)
0

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

>>> bool(1)
True
>>> bool(0)
False
>>> bool(-1)
True
>>> bool('Hello')
True
>>> bool('')
False

В одном из прошлых уроков мы знакомились с типами, и я упомянул, что есть тип None. Он обозначает отсутствие значения. Согласитесь, что есть разница между тем, горит лампочка или не горит, и тем, что она может просто отсутствовать. Преобразование типа None даст следующиее значние:

>>> bool(None)
False

Логический тип и None отличаются, хоть и все три значения — это ключевые слова языка:

>>> type(None)
<class 'NoneType'>
>>> type(True)
<class 'bool'>
>>> None = '1'
  File "<stdin>", line 1
SyntaxError: can't assign to keyword
>>> True = '1'
  File "<stdin>", line 1
SyntaxError: can't assign to keyword

Операторы сравнения

Логический тип — это часто результат выполнения операции сравнения. В школе мы уже сталкивались с ними, и там они назывались математическими неравенствами. Выражения, расположенные по разные стороны оператора принято называть операндами. Давайте посмотрим, как называются операторы в Python и какими символами они обозначаются.

== (равенство)

Этот оператор называется «Проверка на равенство». Он проверяет, равны ли оба операнда и, если да, то он возвращает результат True. Примеры:

  • 7 == 7True
  • True == FalseFalse
  • "hello" == "hello"True

!= (неравенство)

Это оператор «Проверка на равенство». Если оба операнда не равны, то он возвращает результат True. Обратите внимание, что в Python нет оператора <> (больше-меньше). Примеры:

  • 7 != 7False
  • True != FalseTrue
  • "hello" != "hello"False

> (больше), < (меньше), >= (больше или равно), <= (меньше или равно)

Здесь сравниваются значения по обе стороны оператора. В случае, если условие выполняется, оператор возвращает True. Обратите внимание на примеры:

  • 7 > 7False.
  • 10 > 2True.
  • True > FalseTrue. Поскольку числовое значение True равно единице, а False нулю.
  • "a" < "b"True.
  • "земля" != "Земля"True.
  • "земля" > "Земля"True, сравнение строк происходит на основании значений ASCII-кодов символов, поэтому то, что слово «земля», написанное с маленькой буквы считается больше, чем слово «Земля», написанное с большой может сбить с толку.

Логические операторы

and (логическое И)

Это оператор «Логического сравнения истинности обоих значений». Если оба операнда истинны, то возвращается True. Примеры:

  • True and TrueTrue.
  • True and FalseFalse.
  • False and TrueFalse.
  • False and FalseFalse.

or (логическое ИЛИ)

Логическое сравнение истинности хотя бы одного из значений, если оба истинны то возвращает истина. Особенностью работы оператора or является то, что если требуется произвести вычисления для получения логического значения, то после получения первого позитивного значения дальнейшие вычисления не будут производиться. Примеры:

  • True or TrueTrue.
  • True or FalseTrue.
  • False or FalseFalse.

not (логическое НЕ)

Изменяет значение оператора на противоположное. Обычно используется совместно с другими операторами. Примеры:

  • not TrueFalse.
  • True and not FalseTrue.

Оператор вхождения in

Представьте что вам надо проверить пришел ли на концерт уже кто-то по билету с этим номером. В этом случае вам надо получить ответ на вопрос входит ли номер билета в список билетов по которым уже прошли люди в зал, или говоря языком программирования проверить входит ли определенный элемент во множество. Для этих целей в Python есть специальный оператор вхождения.

in (вхождение) и not in

Возвращает истину если элемент присутствует в последовательности. Примеры:

  • 1 in [2, 3, 4]False.
  • 'py' in 'python'True. Поскольку строки являются тоже множествами, то можно проверять вхождение подстроки в другую строку.

Оператор тождественности is

Помимо проверки логики часто надо еще проверить являются ли объекты разными или одним и тем же.

is (тождественен) и not is

Возвращает истину если оба операнда указывают на один и тот же объект в памяти. Внутри оператор сравнивает адреса объектов которые можно получить с помощью функции id. Пример:

>>> x = "Привет"
>>> y = x
>>> x is y
True

Сравнение разных типов

Когда мы сравниваем переменные (операторы >, <, ==, !=, >=, <=), то внутри виртуальной машины интерпретатора запускается специальный код который обрабатывает полученные значения и потом уже проводит операцию сравнения. Например, если мы сравниваем два числа, то где-то внутри Python есть специальная часть которая проверяет первое значение (первый операнд) и узнает, что это число. Потом обрабатывает второй операнд и понимает, что это тоже число. Теперь интерпретатор знает, что это два числа и понимает, что для двух чисел сравнение допустимо и можно применить математические правила.

Если надо сравнить логические типы, то Python считает, что True можно преобразовать в число 1, а False в число 0 и делает сравнение исходя из этих значений.

Для строк вычисляются коды символов в специальных таблицах ASCII или Unicode и проводится сравнение строк посимвольно, как только обнаружится разница, то сравнение прекратится и "выиграет" та строка в которой первой окажется буква с большим индексом. Адрес в таблице у символа можно проверить функцией ord:

>>> 'a' > 'A'
True
>>> ord('a')
97
>>> ord('A')
65

Точно так же как и со строками работает сравнение для списков (list, tuple).

Сравнение множеств (set, frozenset) немного сложнее, и проверяется пересечение элементов множеств. Мы познакомимся более подробно с операциями над множествами в главе про них.

Словари можно только сравнивать на равенство или неравенство. Попытка использовать операторы больше/меньше приведут к ошибке.

Соглашения об истинности для базовых типов данных

Немного сложнее ситуация с логическим сравнением (И, НЕ, ИЛИ). В Python существуют следующие правила:

Если значение переменной равно одному из следующих значений None, 0, 0.0, 0j, '', b'', (), [], {}, то считается, что ее логическое значение равно False

То есть если вы создадие переменную a = 1 и переменную b = True, то результатом a and b будет True.

Особые случаи

Маленькие цифры

Возможно вас немного развлечет следующий пример, он приоткрывает двери в то как внутри устроен интерпретатор Python.

>>> a = 5
>>> b = 5
>>> a == b
True
>>> a is b
True
>>> a2 = 1000
>>> b2 = 1000
>>> a2 == b2
True
>>> a2 is b2
False

Для того чтобы понять почему так, давайте проверим адреса переменных в памяти. Обратите внимание, что значение цифр будет отличаться после перезапуска интерпретатора.

>>> id(a), id(b)
(4353951680, 4353951680)
>>> id(a2), id(b2)
(4361822096, 4361822160)

Почему в первом случае адреса совпадают, а во втором нет? Дело в том, что Python считает, что первые 256 чисел вам точно понадобятся для работы и автоматически выделяет память под них сразу же после запуска интерпретатора, то есть у вас сразу уже есть множество пред созданных переменных. Можно сказать, что на складе памяти изначально не пусто. А когда мы добавляем переменные значения которых на складе нет, то им выделяются новые места в памяти.

Сравнение с None

Сравнение с None имеет более практическое значение. Мы уже сталкивались с правилом определения истинности для переменных разных типов. Если вам нужно сравнить действительно ли значение переменной отсутствует, то лучше использовать сравнение с помощью оператора is:

>>> x = 0
>>> not x
True
>>> x is None
False
>>> y = None
>>> not y
True
>>> y is None
True

После предыдущего примера вы уже знаете, что некоторые переменные в Python инициируются сразу после запуска и находятся в единственном экземпляре в памяти. То же самое и с None, этот объект тоже имеет свое место:

>>> id(None)
4353648936

Поэтому сравнение тождественности is определит что переменная ссылается на тот самый единственный объект None.

Если вы внимательно следили за операторами, то можете предложить сравнить так же с помощью операторов == равенства и != неравенства. Формально это допустимо, но есть особые случаи когда такое сравнение выдаст ошибочный результат. Это тема требует дополнительных объяснений в более продвинутом курсе. Пока проще принять как рекомендацию использовать is. Если вы установили pylint в свой редактор, то скорее всего он предложит переписать условие правильным способом.

Заключение

В этом уроке вы познакомились с логическим типом и операторами сравнения. А так же немного погрузились во внутренности Python и особенности работы с памятью переменных.