Что является результатом is not в python
Перейти к содержимому

Что является результатом is not в python

  • автор:

Логические выражения и операторы

Часто в реальной жизни мы соглашаемся с каким-либо утверждением или отрицаем его. Например, если вам скажут, что сумма чисел 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. Присвойте двум переменным любые числовые значения.
  2. Используя переменные из п. 1, с помощью оператора and составьте два сложных логических выражения, одно из которых дает истину, другое – ложь.
  3. Аналогично выполните п. 2, но уже с оператором or .
  4. Попробуйте использовать в логических выражениях переменные строкового типа. Объясните результат.
  5. Напишите программу, которая запрашивала бы у пользователя два числа и выводила бы True или False в зависимости от того, больше первое число второго или нет.

Примеры решения и дополнительные уроки в pdf-версии курса

X Скрыть Наверх

Python. Введение в программирование

Разбираемся с not в Python

Привет, Хабр. В преддверии старта курса «Python Developer. Professional» подготовили традиционный перевод полезного материала.

В этой статье из серии про синтаксический сахар в Python я займусь на первый взгляд очень простым синтаксисом, но на самом деле, чтобы разобраться в механике его работы, нужно погрузиться вглубь на несколько слоев. Мы будем говорить о not .

Определение звучит на первый взгляд очень просто:

Оператор not выдает True, если его аргумент False, и False в противоположном случае.

Достаточно просто, не так ли? Но когда вы начинаете разбираться в том, что считать «истинным» или «ложным», вы быстро понимаете, что есть приличное количество вещей, подходящих под эти определения.

(Как и в других статьях этой серии, код на С предназначен для тех, кто хочет пройти путь «по хлебным крошкам», но вы можете пропустить его, если хотите)

Реализация not

Если вы посмотрите на байткод, то заметите единственный опкод, относящийся к not – это UNARY_NOT.

>>> import dis >>> def spam(): not a . >>> dis.dis(spam) 1 0 LOAD_GLOBAL 0 (a) 2 UNARY_NOT 4 POP_TOP 6 LOAD_CONST 0 (None) 8 RETURN_VALUE

Реализация UNARY_NOT по сути вызывает функцию С, которая называется PyObject_IsTrue() и возвращает обратное переданному значение: True для False, False для True.

case TARGET(UNARY_NOT): < PyObject *value = TOP(); int err = PyObject_IsTrue(value); Py_DECREF(value); if (err == 0) < Py_INCREF(Py_True); SET_TOP(Py_True); DISPATCH(); >else if (err > 0) < Py_INCREF(Py_False); SET_TOP(Py_False); DISPATCH(); >STACK_SHRINK(1); goto error; >

Определение того, что такое True

Вся хитрость нашего разбора not начинается с определения того, что такое True. Если посмотреть на реализацию PyObject_IsTrue() на языке Си, станет видно, что существует несколько возможных способов выяснить истинность объекта.

/* Test a value used as condition, e.g., in a for or if statement. Return -1 if an error occurred */ int PyObject_IsTrue(PyObject *v) < Py_ssize_t res; if (v == Py_True) return 1; if (v == Py_False) return 0; if (v == Py_None) return 0; else if (v->ob_type->tp_as_number != NULL && v->ob_type->tp_as_number->nb_bool != NULL) res = (*v->ob_type->tp_as_number->nb_bool)(v); else if (v->ob_type->tp_as_mapping != NULL && v->ob_type->tp_as_mapping->mp_length != NULL) res = (*v->ob_type->tp_as_mapping->mp_length)(v); else if (v->ob_type->tp_as_sequence != NULL && v->ob_type->tp_as_sequence->sq_length != NULL) res = (*v->ob_type->tp_as_sequence->sq_length)(v); else return 1; /* if it is negative, it should be either -1 or -2 */ return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); >

Если разбираться в реализации на С, то правило выглядит так:

  1. Если True, то True
  2. Если False, то False
  3. Если None, то False
  4. То, что возвращает bool , до тех пор, пока возвращаемый объект является подклассом bool (то, что показывает вызов nb_bool )
  5. Вызов len() на объекте (то, за что отвечают вызовы mp_length и sq_length ):
    1. Если больше 0, то True
    2. В противном случае False

    Все правила 1-3 и 6 достаточно понятны, а вот правила 4 и 5 требуют углубления в детали.

    Определение специального/волшебного метода bool говорит нам, что метод используется для «реализации проверки истинности значений» и должен возвращать либо True, либо False.

    Встроенная функция len() возвращает целое число, представляющее количество элементов в контейнере. Реализация вычисления длины объекта представлена слотами sq_length (длина последовательностей) и mp_length (длина словарей/мэпов).

    Легко подумать, что к объекту можно просто обратиться и запросить его длину, но тут есть два слоя.

    Первый слой – это специальный/волшебный метод len . Как и следовало ожидать, он «должен возвращать длину объекта, целое число >= 0». Но дело в том, что «целочисленный» не означает int , а означает объект, который вы можете «преобразовать без потерь»… к «целочисленному объекту». И как же выполнить это преобразование?

    «Чтобы без потерь преобразовать численный объект в целочисленный», используется специальный/волшебный метод index . В частности, для обработки преобразования используется функция PyNumber_Index() . Эта функция слишком длинная, чтобы ее сюда вставлять, но делает она следующее:

    1. Если аргумент является экземпляром класса int , вернуть его
    2. В противном случае вызвать index на объекте
    3. Если index возвращает конкретный экземпляр класса int , вернуть его (технически возвращать подкласс не рекомендуется, но давайте оставим это в прошлом).
    4. В противном случае вернуть TypeError .

    На уровне Python это делается с помощью operator.index() . К сожалению, здесь не реализуется семантика PyNumber_Index() , поэтому на самом деле с точки зрения not и len , функция работает немного неточно. Если бы она все же была реализована, то выглядела бы так:

    Реализация PyNumber_Index() на Python:

    def index(obj: Object, /) -> int: """Losslessly convert an object to an integer object. If obj is an instance of int, return it directly. Otherwise call __index__() and require it be a direct instance of int (raising TypeError if it isn't). """ # https://github.com/python/cpython/blob/v3.8.3/Objects/abstract.c#L1260-L1302 if isinstance(obj, int): return obj length_type = builtins.type(obj) try: __index__ = _mro_getattr(length_type, "__index__") except AttributeError: msg = ( f" cannot be interpreted as an integer " "(must be either a subclass of 'int' or have an __index__() method)" ) raise TypeError(msg) index = __index__(obj) # Returning a subclass of int is deprecated in CPython. if index.__class__ is int: return index else: raise TypeError( f"the __index__() method of returned an object of " f"type , not 'int'" )

    Реализация len()

    Еще один интересный факт о реализации len() : она всегда возвращает конкретный int . Так, несмотря на то, что index() или len() могут возвращать подкласс, ее реализация на уровне С через PyLong_FromSsize_t() гарантирует, что всегда будет возвращаться конкретный экземпляр int .

    В противном случае len() будет проверять, что возвращают len() и index () , например, является ли возвращаемый объект подклассом int , больше ли значение или равно 0 и т.д. Таким образом, вы можете реализовать len() так:

    def len(obj: Object, /) -> int: """Return the number of items in a container.""" # https://github.com/python/cpython/blob/v3.8.3/Python/bltinmodule.c#L1536-L1557 # https://github.com/python/cpython/blob/v3.8.3/Objects/abstract.c#L45-L63 # https://github.com/python/cpython/blob/v3.8.3/Objects/typeobject.c#L6184-L6209 type_ = builtins.type(obj) try: __len__ = _mro_getattr(type_, "__len__") except AttributeError: raise TypeError(f"type does not have a __len__() method") length = __len__(obj) # Due to len() using PyObject_Size() (which returns Py_ssize_t), # the returned value is always a direct instance of int via # PyLong_FromSsize_t(). index = int(_index(length)) if index < 0: raise ValueError("__len__() should return >= 0") else: return index

    Реализация operator.truth()

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

    В Python нам не нужна эта идиома. Спасибо bool() (а конкретно bool.new() ), за то, что у нас есть вызов функции, который мы можем использовать для получения конкретного логического значения, а именно operator.truth() . Если вы посмотрите на этот метод, то увидите, что он использует PyObject_IsTrue() для определения логического значения объекта. Посмотрев slot_nb_bool () , вы увидите, что в конечном итоге он делает то же, что и PyObject_IsTrue() . То есть, если мы можем реализовать аналог PyObject_IsTrue() , то можем определить, какое логическое значение имеет объект.

    По старой схеме и с тем, что мы узнали только что, мы можем реализовать operator.truth() для этой логики (я предпочитаю не реализовывать bool , поскольку не хочу реализовывать все его численные функции, и не придумал хорошего способа сделать True и False с нуля, которые наследовались бы от 1 и 0 на чистом Python).

    def truth(obj: Any, /) -> bool: """Return True if the object is true, False otherwise. Analogous to calling bool(). """ if obj is True: return True elif obj is False: return False elif obj is None: return False obj_type = type(obj) try: __bool__ = debuiltins._mro_getattr(obj_type, "__bool__") except AttributeError: # Only try calling len() if it makes sense. try: __len__ = debuiltins._mro_getattr(obj_type, "__len__") except AttributeError: # If all else fails. return True else: return True if debuiltins.len(obj) > 0 else False else: boolean = __bool__(obj) if isinstance(boolean, bool): # Coerce into True or False. return truth(boolean) else: raise TypeError( f"expected a 'bool' from .__bool__(), " f"not " )

    Реализация not

    С реализованным оператором operator.truth() , реализовать operator.not_() – дело всего одной лямбды:

    lambda a, /: False if truth(a) else True

    Итоговый результат прост, но, чтобы добраться до него, нужно было проделать немало работы.

    Как обычно, код из этой статьи можно найти в моем проекте desugar.

    Python: Отрицание

    Наряду с логическими операторами И и ИЛИ, часто используется операция «отрицание». Она меняет логическое значение на противоположное. В программировании отрицанию соответствует унарный оператор not :

    not True # False not False # True 

    Например, если есть функция, которая проверяет четность числа, то с помощью отрицания можно выполнить проверку нечетности:

    def is_even(number): return number % 2 == 0 print(is_even(10)) # => True print(not is_even(10)) # => False 

    В примере выше мы добавили not слева от вызова функции и получили обратное действие.

    Отрицание — инструмент, с которым можно выражать задуманные правила в коде и не писать новые функции.

    Если написать not not is_even(10) , то код сработает даже в таком случае:

    print(not not is_even(10)) # => True 

    В логике двойное отрицание — это отсутствие отрицания:

    not not True # True not not False # False print(not not is_even(10)) # => True print(not not is_even(11)) # => False 

    Теперь вы знаете, что означают операторы И, ИЛИ и not . С их помощью вы сможете задавать составные условия из двух и более логических выражений.

    Задание

    В этом уроке вам нужно будет реализовать две функции is_palindrome() и is_not_palindrome() , принимающие строку на вход

      Реализуйте функцию is_palindrome() , которая определяет, является ли слово палиндромом или нет. Палиндром - это слово, которое читается одинаково в обоих направлениях. Слова в функцию могут быть переданы в любом регистре, поэтому сначала нужно привести слово к нижнему регистру: word.lower() .

    is_palindrome('шалаш') # true is_palindrome('хекслет') # false is_palindrome('Довод') # true is_palindrome('Функция') # false 
    is_not_palindrome('шалаш') # false is_not_palindrome('Ага') # false is_not_palindrome('хекслет') # true 

    Упражнение не проходит проверку — что делать? ��

    Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

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

    В моей среде код работает, а здесь нет ��

    Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

    Мой код отличается от решения учителя ��

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

    В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

    Прочитал урок — ничего не понятно ��

    Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

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

    Полезное

    Определения

    • Отрицание — логическая операция, которая меняет логическое значение на противоположное.

    Условный оператор

    Проверьте истинность второго отношения при подстановке следующих значений:

    Определение. Выражение, о котором после подстановки в него значений переменных можно сказать, истинно (верно) оно или ложно (неверно), называется булевым (логическим) выражением.

    Примечание. Название “булевы” произошло от имени математика Джорджа Буля, разработавшего в XIX веке булеву логику и алгебру логики.

    Определение. Переменная, которая может принимать одно из двух значений: True (правда) или False (ложь), называется булевой (логической) переменной. Например,

    К:=True;
    Flag:=False;
    Second:=a+sqr(x)>t

    Задача. Вычислить значение модуля и квадратного корня из выражения (х-у).

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

    Koren:=Sqrt(x-y);
    Modul:=Abs(x-y)

    В этом случае программа будет иметь вид:

    Program Znachenia;
    Uses
    Crt;
    Var
    x, y : integer;
    Koren, Modul : real;
    Begin
    ClrScr;
    write ('Введите значения переменных х и у через пробел ');
    readln (x, y);
    Koren:=Sqrt(x-y);
    Modul:=Abs(x-y);
    write ('Значение квадратного корня из выражения (х-у) равно ', Koren);
    write ('Значение модуля выражения (х-у) равно ', Modul);
    readln;
    End.

    Казалось бы, задача решена. Но мы не учли области допустимых значений для нахождения квадратного корня и модуля. Из курса математики Вы должны знать, что можно найти модуль любого числа, а вот значение подкоренного выражения должно быть неотрицательно (больше или равно нулю).

    Поэтому наша программа имеет свою допустимую область исходных данных. Найдем эту область. Для этого запишем неравенство х-у>=0, то есть х>=у. Значит, если пользователем нашей программы будут введены такие числа, что при подстановке значение этого неравенства будет равно True, то квадратный корень из выражения (х-у) извлечь можно. А если значение неравенства будет равно False, то выполнение программы закончится аварийно.

    Задание. Наберите текст программы. Протестируйте программу со следующими значениями переменных и сделайте вывод.

    1. х=23, у=5;
    2. х=-5, у=15;
    3. х=8, у=8.

    Каждая программа, насколько это возможно, должна осуществлять контроль за допустимостью величин, участвующих в вычислениях. Здесь мы сталкиваемся с разветвлением нашего алгоритма в зависимости от условия. Для реализации таких условных переходов в языке Паскаль используют операторы If и Case, а также оператор безусловного перехода Goto.

    Рассмотрим оператор If.

    Для нашей задачи нужно выполнить следующий алгоритм:

    если х>=у,
    то вычислить значение квадратного корня,
    иначе выдать на экран сообщение об ошибочном введении данных.

    Запишем его с помощью оператора If. Это будет выглядеть так.

    if x>=y
    then
    Koren:=Sqr(x-y)
    else
    write ('Введены недопустимые значения переменных');

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

    В общем случае полная форма конструкции условного оператора имеет вид:

    Условный оператор работает по следующему алгоритму.

    Сначала вычисляется значение логического выражения, расположенного за служебным словом IF. Если его результат истина, выполняется , расположенный после слова THEN, а действия после ELSE пропускаются; если результат ложь, то, наоборот, действия после слова THEN пропускаются, а после ELSE выполняется .

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

    Если в качестве оператора должна выполниться серия операторов, то они заключаются в операторные скобки begin-end. Конструкция Begin . End называется составным оператором.

    if
    then
    begin
    оператор 1;
    оператор 2;
    .
    end
    else
    begin
    оператор 1;
    оператор 2;
    .
    end;

    Определение. Составной оператор - объединение нескольких операторов в одну группу. Группа операторов внутри составного оператора заключается в операторные скобки (begin-end).

    begin
    оператор 1;
    оператор 2;
    end;

    С учетом полученных знаний преобразуем нашу программу.

    Program Znachenia;
    Uses
    Crt;
    Var
    x, y : integer;
    Koren, Modul : real;
    Begin
    ClrScr;
    write ('Введите значения переменных х и у через пробел ');
    read (x, y);
    if x>=y
    then
    begin
    Koren:=Sqr(x-y);
    Modul:=Abs(x-y);
    write ('Значение квадратного корня из выражения (х-у) равно ', Koren);
    write ('Значение модуля выражения (х-у) равно ', Modul);
    end
    else
    write ('Введены недопустимые значения переменных');
    readln;
    End.

    Составным оператором является и такой оператор

    begin
    S:=0;
    end.

    Cимвол “;” в данном случае разделяет оператор присваивания S:=0 и пустой оператор.

    Пустой оператор не влечет никаких действий и в записи программы никак не обозначается.

    Например, составной оператор

    включает лишь один пустой оператор.

    Если Вы обратили внимание, программа на языке Паскаль всегда содержит один составной оператор - раздел операторов программы.

    Внимание! Перед служебным словом Else разделитель (точка с запятой) не ставится.

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

      Каждое описание переменной и определение константы заканчиваются точкой с запятой.

    Рассмотрим еще один пример.

    Задача. Вывести на экран большее из двух данных чисел.

    Program Example1;
    Var
    x, y : integer;
    Begin
    writeln('Введите 2 числа ');
    readln(x,y);
    if x>y
    then
    writeln (x)
    else
    writeln (y);
    readln;
    End.

    Можно также использовать и сокращенную (неполную) форму записи условного оператора. Эта форма используется тогда, когда в случае невыполнения условия ничего делать не надо.

    Неполная форма условного оператора имеет следующий вид.

    Тогда если выражение, расположенное за служебным словом IF. в результате дает истину, выполняются действия после слова THEN, в противном случае эти действия пропускаются.

    Задача. Составить программу, которая, если введенное число отрицательное, меняет его на противоположное.

    Program Chisla;
    Var
    x : integer;
    Begin
    writeln('Введите число ');
    readln(x);
    if x then
    x:=-x;
    writeln (x);
    readln;
    End.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *