Рубрики
Без рубрики

Под капотом: нарушение сравнения Python

Используйте модуль Python «DS», чтобы увидеть, как Python оценивает две аналогичные операции сравнения. Теги с Python, Dis, Bytecode.

Этот пост изначально появился как Гостевая статья о пибитах .

Участник сообщества Pybites fusionmuck Недавно задал интересный вопрос в слабым каналам:

Я пытаюсь вернуть голову вокруг порядка приоритета. Тестовый код перечислен без скобок. Во второй части я добавляю кронштейны для проверки моего понимания приоритета, и я получаю возвращаемое значение true. Я что-то упускаю здесь …

Сопровождается этот образец кода:

>>> lst = [2, 3, 4] 
>>> lst[1] * -3 < -10 == 0 
False 

>>> (((lst[1]) * (-3)) < (-10)) == 0 
True

Я люблю этот вопрос, потому что есть несколько разных концепций, но Fusionmumck все еще есть ясный вопрос – «Почему Python делает Это Когда я ожидаю, что это делать что ? “

Когда я увидела вопрос, я думал, что понял хотя бы часть того, что происходит. Мне нужно было проверить некоторые чеки, чтобы быть уверенным, и это веселые вещи, чтобы играть с. Так что давайте сделаем это вместе!

  1. Упрощать
  2. Читать или экспериментировать?
  3. Мстители … Разборка!
  4. Бонус раунд: снаружи Python
  5. Вынос и связанные с этим чтение

Упрощать

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

  • Вытягивание предметов из списка
  • Использование 0 как логическое (True/false) значение
  • Отрицательные номера

И придумать пару более простых сравнений, которые все еще демонстрируют поведение из оригинального вопроса:

>>> 3 < 1 == False
False 

>>> (3 < 1) == False
True

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

Читать или экспериментировать?

Оригинальный вопрос был о приоритете оператора в Python. Один из способов ответить на этот вопрос – проверить официальную документацию Python. Разделы на Оператор приоритет и Сравнение цепочки Определенно полезны:

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

А также:

Сравнения могут быть приведены произвольно, например, x

Формально, если a, b, c, …, y, z – это выражения и OP1, OP2, …, OPN – операторы сравнения, затем OP1 B OP2 C … y Opn z эквивалентно OP1 B и B OP2 C и … y opn z, за исключением того, что каждое выражение оценивается не более одного раза.)

Применение того, что к нашему вопросу, это означает для сравнения, как это:

3 < 1 == False

Python относится к этому так:

3 < 1 and 1 == False

Это делает вещи намного яснее! Добавление скобок помогает превратить прикованный сравнение на отдельные явными упорядоченными операциями.

Но … что, если мы хотим увидеть эту разницу в действии? Что происходит под капотом, когда мы добавляем эти скобки? Мы больше не можем сломать код, пока сохраняя поведение, которое мы пытаемся наблюдать, поэтому Печать () Заявления или отладки Python имеют ограниченное использование. Но у нас все еще есть способы выглядеть ближе.

Мстители … Разборка!

Питона дес Модуль может помочь нам разбить код Python во внутренние инструкции ( Bytecode ), что интерпретатор Cpython видит. Это может быть очень полезно для понимания того, как работает Python Code. Чтение Разборка вывода может быть сначала сложно, но вам не нужно понимать каждую деталь для обнаружения различий между двумя кусками кода.

Итак, давайте посмотрим на некоторые байт-код для этих двух сравнений. И если это ваш первый раз, когда вы смотряте в разобранном виде Python, не паникуйте! Сосредоточьтесь на том, насколько дольше первый блок инструкции:

>>> import dis
>>> dis.dis('3 < 1 == False')
  1           0 LOAD_CONST               0 (3)
              2 LOAD_CONST               1 (1)
              4 DUP_TOP
              6 ROT_THREE
              8 COMPARE_OP               0 (<)
             10 JUMP_IF_FALSE_OR_POP    18
             12 LOAD_CONST               2 (False)
             14 COMPARE_OP               2 (==)
             16 RETURN_VALUE
        >>   18 ROT_TWO
             20 POP_TOP
             22 RETURN_VALUE

>>> dis.dis('(3 < 1) == False')
  1           0 LOAD_CONST               0 (3)
              2 LOAD_CONST               1 (1)
              4 COMPARE_OP               0 (<)
              6 LOAD_CONST               2 (False)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

Эти дополнительные инструкции в первом блоке работают Python, чтобы управлять Chicked сравнения Отказ Есть весело играть с дес – Отправьте его какой-нибудь код, который вы понимаете, или некоторые, которые вы не (все же)!

Вот некоторые анимации домохозяйств, которые циклически проходят инструкции Bytecode, показывая стек оценки по пути. Если вы хотите следить со ссылкой, Этот раздел из дес Документация объясняет, как каждая инструкция по Bytecode взаимодействует с стеком оценки.

Вот разбивка 3 <1 ( Полноразмерный ):

И вот (3 < 1) ( Полноразмерный ):

Это было много слов и фотографий, чтобы сломать две операции сравнения, но я надеюсь, что вам повеселись по пути.

Бонус раунд: снаружи Python

Один хитрый аспект этого вопроса в том, что == и < имеют одинаковый приоритет. Часто это не актуально, потому что вы бы вряд ли напечатаете:

if a < b == False:
    ...

Когда вы можете использовать проще:

if a >= b:
    ...

или:

if not a < b:
    ...

Если вы приедете к Python с другого языка, правильные правила приоритета оператора Python могут уловить вас от гвардии. На языках, таких как C, C #, Java и JavaScript, реляционные сравнения, такие как < иметь более высокий приоритет, чем проверки равенства, как ==. . Это делает 3 <1 Функционально эквивалентно (3 < 1) . Ржавчина Отклоняет эту путаницу полностью, заставляя вас быть явным:

Скобки требуются при цепочке операторов сравнения. Например, выражение A недействителен и может быть записан как (а).

Вынос и связанные с этим чтение

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

Пост, который вдохновил я вытащить дес Модуль чаще был:

Странные целые числа Python Часть II: Константы в Bytecode Кейт Мерфи

Спасибо за прочтение! Пожалуйста, оставьте какие-либо вопросы или комментарии ниже, особенно если вы знаете лучший способ создания анимации стека оценки из Python Bytecode.

Сохраняйте спокойствие и код в Python!

– AJ.

Оригинал: “https://dev.to/ajkerrigan/under-the-hood-python-comparison-breakdown-3job”