Логические выражения и операторы
Часто в реальной жизни мы соглашаемся с каким-либо утверждением или отрицаем его. Например, если вам скажут, что сумма чисел 3 и 5 больше 7, вы согласитесь, скажете: «Да, это правда». Если же кто-то будет утверждать, что сумма трех и пяти меньше семи, то вы расцените такое утверждение как ложное.
Подобные фразы предполагают только два возможных ответа – либо «да», когда выражение оценивается как правда/истина, либо «нет», когда утверждение оценивается как ошибочное/ложное. В программировании и математике если результатом вычисления выражения может быть лишь истина или ложь, то такое выражение называется логическим.
Например, выражение 4 > 5 является логическим, так как его результатом является либо правда, либо ложь. Выражение 4 + 5 не является логическим, так как результатом его выполнения является число.
На позапрошлом уроке мы познакомились с тремя типами данных – целыми и вещественными числами, а также строками. Сегодня введем четвертый – логический тип данных (тип bool ). Его также называют булевым. У этого типа всего два возможных значения: True (правда) и False (ложь).
>>> a = True >>> type(a) >>> b = False >>> type(b)
Здесь переменной a было присвоено значение True , после чего с помощью встроенной в Python функции type() проверен ее тип. Интерпретатор сообщил, что это переменная класса bool . Понятия «класс» и «тип данных» в данном случае одно и то же. Переменная b также связана с булевым значением.
В программировании False обычно приравнивают к нулю, а True – к единице. Чтобы в этом убедиться, можно преобразовать булево значение к целочисленному типу:
>>> int(True) 1 >>> int(False) 0
Возможно и обратное. Можно преобразовать какое-либо значение к булевому типу:
>>> bool(3.4) True >>> bool(-150) True >>> bool(0) False >>> bool(' ') True >>> bool('') False
И здесь работает правило: всё, что не 0 и не пустота, является правдой.
Логические операторы
Говоря на естественном языке (например, русском) мы обозначаем сравнения словами «равно», «больше», «меньше». В языках программирования используются специальные знаки, подобные тем, которые используются в математике: > (больше), < (меньше), >= (больше или равно),
Не путайте операцию присваивания значения переменной, обозначаемую в языке Python одиночным знаком «равно», и операцию сравнения (два знака «равно»). Присваивание и сравнение – разные операции.
>>> a = 10 >>> b = 5 >>> a + b > 14 True >>> a < 14 - b False >>> a >> a != b True >>> a == b False >>> c = a == b >>> a, b, c (10, 5, False)
В данном примере выражение c = a == b состоит из двух подвыражений. Сначала происходит сравнение ( == ) переменных a и b . После этого результат логической операции присваивается переменной c . Выражение a, b, c просто выводит значения переменных на экран.
Сложные логические выражения
Логические выражения типа kbyte >= 1023 являются простыми, так как в них выполняется только одна логическая операция. Однако, на практике нередко возникает необходимость в более сложных выражениях. Может понадобиться получить ответа «Да» или «Нет» в зависимости от результата выполнения двух простых выражений. Например, «на улице идет снег или дождь», «переменная news больше 12 и меньше 20».
В таких случаях используются специальные операторы, объединяющие два и более простых логических выражения. Широко используются два оператора – так называемые логические И (and) и ИЛИ (or).
Чтобы получить True при использовании оператора and , необходимо, чтобы результаты обоих простых выражений, которые связывает данный оператор, были истинными. Если хотя бы в одном случае результатом будет False , то и все сложное выражение будет ложным.
Чтобы получить True при использовании оператора or , необходимо, чтобы результат хотя бы одного простого выражения, входящего в состав сложного, был истинным. В случае оператора or сложное выражение становится ложным лишь тогда, когда ложны оба составляющие его простые выражения.
Допустим, переменной x было присвоено значение 8 ( x = 8 ), переменной y присвоили 13 ( y = 13 ). Логическое выражение y < 15 and x >8 будет выполняться следующим образом. Сначала выполнится выражение y < 15 . Его результатом будет True . Затем выполнится выражение x >8 . Его результатом будет False . Далее выражение сведется к True and False , что вернет False .
>>> x = 8 >>> y = 13 >>> y < 15 and x >8 False
В случае с оператором or второе простое выражение проверяется, если первое вернуло ложь, и не проверяется, если уже первое вернуло истину. Так как для истинности всего выражения достаточно единственного True , неважно по какую сторону от or оно стоит.
>>> y < 15 or x >8 True
В языке Python есть еще унарный логический оператор not , то есть отрицание. Он превращает правду в ложь, а ложь в правду. Унарный он потому, что применяется к одному выражению, стоящему после него, а не справа и слева от него как в случае бинарных and и or .
>>> not y < 15 False
>>> a = 5 >>> b = 0 >>> not a False >>> not b True
Число 5 трактуется как истина, отрицание истины дает ложь. Ноль приравнивается к False . Отрицание False дает True .
Практическая работа
- Присвойте двум переменным любые числовые значения.
- Используя переменные из п. 1, с помощью оператора and составьте два сложных логических выражения, одно из которых дает истину, другое – ложь.
- Аналогично выполните п. 2, но уже с оператором or .
- Попробуйте использовать в логических выражениях переменные строкового типа. Объясните результат.
- Напишите программу, которая запрашивала бы у пользователя два числа и выводила бы True или False в зависимости от того, больше первое число второго или нет.
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование
python Разница между == (равно) и is (эквивалентность)
![]()
Из М. Лутца:
Первый способ, основанный на использовании оператора ==, проверяет, равны
ли значения объектов. В языке Python практически всегда используется именно этот способ.
Второй способ, основанный на использовании оператора is, проверяет идентичность объектов. Он возвращает значение True, только если оба имени ссылаются на один и тот же объект, вследствие этого он является более
строгой формой проверки равенства.
Key Words for FKN + antitotal forum (CS VSU):
Python: is. Равенство и эквивалентность
Новички часто путаются в конструкциях is и == . Давайте разберемся, что к чему.
Сразу к сути: == (и его антагонист != ) применяются для проверки равенства (неравенства) значения двух объектов. Значение, это непосредственно то, что лежит в переменной. Значение числа 323235 – собственно число 323235. Тавтология. Но на примерах станет яснее.
Оператор is (и его антагонист is not ) применяются проверки равенства (неравенства) ссылок на объект. Сразу отметим то, что на значение (допустим 323235) может быть копировано и храниться в разных местах (в разных объектах в памяти).
>> x = 323235 >> y = 323235 >> x == y True >> x is y False
Видите, значение переменных равны по значению, но они ссылаются на разные объекты. Я не случайно взял большое число 323235. Дело в том, что в целях оптимизации интерпретатор Python при старте создает некоторые количество часто-используемых констант (от -5 до 256 включительно).
Следите внимательно за ловкостью рук:
>>> x = 256 >>> y = 256 >>> x is y True >>> x = 257 >>> y = 257 >>> x is y False >>> x = -5 >>> y = -5 >>> x is y True >>> x = -6 >>> y = -6 >>> x is y False
Поэтому новички часто совершают ошибку, считая, что писать == – это как-то не Python-way, а is – Python-way. Это ошибочное предположение может быть раскрыто не сразу.
Python старается кэшировать и переиспользовать строковые значения. Поэтому весьма вероятно, что переменные, содержащие одинаковые строки, будут содержать ссылки на одинаковые объекты. Но это не факт! Смотрите последний пример:
>>> x = "hello" >>> y = "hello" >>> x is y True >>> x = "hel" + "lo" >>> y = "hello" >>> x is y True >>> a = "hel" >>> b = "lo" >>> x = a + b >>> y = "hello" >>> x == y True >>> x is y False
Мы составили строку из двух частей и она попала в другой объект. Python не догадался (и правильно) поискать ее в существующих строках.
Суть is (id)
В Python есть встроенная функция id . Она возвращает идентификатор объекта – некоторое число. Гарантируется, что оно будет различно для различных объектах в пределах одного интерпретатора. В реализации CPython – это просто адрес объекта в памяти интерпретатора.
a is b
Это тоже самое, что:
id(a) == id(b)
И все! Пример для проверки:
>>> x = 10.40 >>> y = 10.40 >>> x is y False >>> x == y True >>> id(x) 4453475504 >>> id(y) 4453475600 >>> id(x) == id(y) False >>> x = y >>> x is y True >>> id(x) 4453475600 >>> id(y) 4453475600
Значения переменных равны, но их id – разные, и is выдает False . Как только мы к x привязали y , то ссылки стали совпадать.
Для чего можно применять is?
Если мы точно знаем уверены, что хотим проверять именно равенство ссылок на объекты (один ли это объект в памяти или разные).
Еще можно применять is для сравнения с None . None – это встроенная константа и двух None быть не может.
>>> x is None False >>> x = None >>> x is None True
Также для Ellipsis:
>>> . is Ellipsis True >>> x = . >>> y = . >>> x is y True
Я не рекомендую применять is для True и False .
Потому что короче писать if x: , чем if x is True: .
Можно применять is для сравнения типов с осторожностью (без учета наследования, т. е. проверка на точное совпадение типов):
>>> x = 10.5 >>> type(x) is float True
С наследованием может быть конфуз:
>>> class Foo: . . >>> class Bar(Foo): . . >>> f = Foo() >>> b = Bar() >>> type(f) is Foo True >>> type(b) is Bar True >>> type(b) is Foo False >>> isinstance(b, Foo) True
Не смотря на то, что Bar – наследник Foo , типы переменных foo и bar не совпадают. Если нам важно учесть наcледование, то пишите isinstance .
Нюанс: is not против is (not)
Важно знать, что is not – это один целый оператор, аналогичный id(x) != id(y) . А в конструкции x is (not y) – у нас сначала будет логическое отрицание y , а потом просто оператор is .
>>> x = 10 >>> x is not None True >>> x is (not None) False
Сравнение пользовательских классов
Далее речь пойдет об обычных == и != . Можно определить магический метод __eq__ , который обеспечит поведение при сравнении классов. Если он не реализован, то объекты будет сравниваться по ссылкам (как при is ).
>>> class Baz: . . >>> x = Baz() >>> y = Baz() >>> x == y False >>> x = y >>> x == y True
Если он реализован, то будет вызван метод __eq__ для левого операнда.
class Foo: def __init__(self, x): self.x = x def __eq__(self, other): print('Foo __eq__ <> and <>'.format(self, other)) return self.x == other.x >>> x = Foo(5) >>> y = Foo(5) >>> x == y Foo __eq__ and True
Метод __ne__ отвечает за реализацию != . По умолчанию он вызывает not x.__eq__(y) . Но рекомендуется реализовывать их оба вручную, чтобы поведение сравнения было согласовано и явно.
Вопрос к размышлению: что будет если мы сравним объекты разных классов, причем оба класса реализуют __eq__ ?
Что будет, если мы реализуем __ne__ , но не реализуем __eq__ ?
А еще есть метод __cmp__ . Это уже выходит за рамки статьи про is . Почитайте самостоятельно…
Таблица истинности которая считывает функцию Python
Чтобы не парсить выражение, можно привлечь Питон вычислять введённую функцию и заполнять таблицу истинности. Для этого завести класс, который будет представлять переменные в выражении, и у него переопределить соответствующие операторы. А дальше инициализировать переменные всеми возможными значениями и получать результат введённой функции для каждого набора значений переменных при помощи штатной функции eval() .
import re class BoolVar: def __init__(self, value): self.value = value #print("INIT =", value) # '-' — возражения "нет" def __neg__(self): return BoolVar(not self.value) # '+' — дизъюнкция "или" def __add__(self, other): return BoolVar(self.value or other.value) # '*' — конъюнкция "и" def __mul__(self, other): return BoolVar(self.value and other.value) # '>' — импликация "если . тогда" def __gt__(self, other): return BoolVar((not self.value) or other.value) # '=' — эквивалентность "ровно" def __eq__(self, other): return BoolVar(self.value == other.value) # строковое представление значения def __str__(self): return "True" if self.value else "False" def __format__(self, format_spec): return format(str(self), format_spec) infunc = input('Enter your function: ') # в питоне знак эквивалентности - это '==', так что заменяем infunc = infunc.replace("=", "==") # находим переменные в функции, т.е. просто буквы # set() делает этот набор уникальным, ну и сортируем variables = sorted(set(re.findall(r"[A-Za-z]", infunc))) # или так, если надо без использования регулярных выражений # variables = sorted(set([c for c in infunc if c.isalpha()])) # просто красивое оформление для таблицы header = [""]*2 for key in variables: header[0] += "-"*7 + "+" header[1] += f" |" header[0] += "-+" + "-"*7 header[1] += " | Result" print("\n".join(header + header[0:1])) vars_for_eval = <> # вариантов входных значений для таблицы - 2 в степени кол-ва переменных for variant in range(1 ", end=" |") # вычисляем результат result = eval(infunc, <>, vars_for_eval) print(f" | ") print(header[0])
Оно даже чего-то считает:
D:\Programming\Python\1>python bools.py Enter your function: a+b -------+-------+-+------- a | b | | Result -------+-------+-+------- False | False | | False False | True | | True True | False | | True True | True | | True -------+-------+-+------- D:\Programming\Python\1>python bools.py Enter your function: -x=y -------+-------+-+------- x | y | | Result -------+-------+-+------- False | False | | False False | True | | True True | False | | True True | True | | False -------+-------+-+------- D:\Programming\Python\1>python bools.py Enter your function: -p+(p*q)=q -------+-------+-+------- p | q | | Result -------+-------+-+------- False | False | | False False | True | | True True | False | | True True | True | | True -------+-------+-+-------
Кстати, программу заодно можно использовать как калькулятор. 🙂
D:\Programming\Python\1>python bools.py Enter your function: 55*23-16**5//16 -+------- | Result -+------- | -64271 -+-------