То, что вы видите во всех трех экземплярах, является следствием грамматической спецификации языка и того, как токены, встречающиеся в исходном коде, анализируются для создания дерева синтаксического анализа.
Взгляд на этот низкоуровневый код должен помочь вам понять, что происходит под капотом. Мы можем взять эти операторы python, преобразовать их в байтовый код, а затем декомпилировать их с помощью dis
модуля:
Случай 1: (0, 0) == 0, 0
>>> dis.dis(compile("(0, 0) == 0, 0", '', 'exec'))
1 0 LOAD_CONST 2 ((0, 0))
3 LOAD_CONST 0 (0)
6 COMPARE_OP 2 (==)
9 LOAD_CONST 0 (0)
12 BUILD_TUPLE 2
15 POP_TOP
16 LOAD_CONST 1 (None)
19 RETURN_VALUE
(0, 0)
сначала сравнивается с 0
первым и оценивается False
. Затем создается кортеж с этим последним результатом 0
, так что вы получаете (False, 0)
.
Случай 2: 0, 0 == (0, 0)
>>> dis.dis(compile("0, 0 == (0, 0)", '', 'exec'))
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 0 (0)
6 LOAD_CONST 2 ((0, 0))
9 COMPARE_OP 2 (==)
12 BUILD_TUPLE 2
15 POP_TOP
16 LOAD_CONST 1 (None)
19 RETURN_VALUE
Кортеж строится с 0
первым элементом. Для второго элемента выполняется та же проверка, что и в первом случае, и вычисляется значение False
, поэтому вы получаете (0, False)
.
Случай 3: (0, 0) == (0, 0)
>>> dis.dis(compile("(0, 0) == (0, 0)", '', 'exec'))
1 0 LOAD_CONST 2 ((0, 0))
3 LOAD_CONST 3 ((0, 0))
6 COMPARE_OP 2 (==)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
Здесь, как вы видите, вы просто сравниваете эти два (0, 0)
кортежа и возвращаетесь True
.