Python не должен ничего преобразовывать и не может, если захочет.
Условное выражение анализируется с помощью грамматики языка в абстрактном синтаксическом дереве , которое, в свою очередь, затем компилируется в байт-код. Вы можете произвести AST с помощью функции ast.parse()
:
>>> import ast
>>> ast.parse('c = a if condition else b').body[0] # first statement in the tree
<_ast.Assign object at 0x10f05c550>
>>> ast.dump(ast.parse('c = a if condition else b').body[0])
"Assign(targets=[Name(id='c', ctx=Store())], value=IfExp(test=Name(id='condition', ctx=Load()), body=Name(id='a', ctx=Load()), orelse=Name(id='b', ctx=Load())))"
Обратите внимание на узел ast.IfExp()
в AST, созданный для назначения; это выделенный узел для условных выражений. Он состоит из частей test
, body
и orelse
, представляющих 3 выражения, составляющие части условия, истину и ложь. Это задокументировано в модуле ast
Абстрактная грамматика раздел :
expr = [...]
| [...]
| IfExp(expr test, expr body, expr orelse)
Это показывает, что типом каждого элемента является другой expr
узел выражения.
Затем дерево разбора компилируется в байт-код, который использует стек для условного перехода к правой части на основе теста; мы можем передать AST, создаваемый ast.parse()
, напрямую в функцию compile()
, после чего модуль dis
позволяет нам взглянуть на удобную для человека форму производимого байт-кода по компиляции:
>>> import dis
>>> dis.dis(compile(ast.parse('c = a if condition else b'), '', 'exec'))
1 0 LOAD_NAME 0 (condition)
2 POP_JUMP_IF_FALSE 8
4 LOAD_NAME 1 (a)
6 JUMP_FORWARD 2 (to 10)
>> 8 LOAD_NAME 2 (b)
>> 10 STORE_NAME 3 (c)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
Таким образом, если условие ложно, цикл интерпретатора переходит к инструкции 8, в противном случае инструкции 4 и 6 выполняются, а инструкция 6 переходит к инструкции 10 (то есть после выражения else
). Конечным результатом является то, что либо инструкция 4, либо инструкция 8 помещают новый результат в начало стека, чтобы STORE_NAME
мог перейти к переменной.
Оператор if
приводит к другому узлу AST, и результирующий байт-код оказывается очень похожим в том смысле, что он тоже будет использовать переходы. Но компилятор обрабатывает их как отдельные части синтаксиса, и он имеет до.
Выражения и операторы являются двумя очень разными фундаментальными строительными блоками языка программирования. Выражения могут содержать выражения, но выражения не могут содержать выражения, только другие выражения. И выражения могут создавать значение (для использования окружающего синтаксиса), но операторы не могут . Таким образом, Python должен относиться к условным выражениям очень иначе, чем к операторам, в том смысле, что синтаксический анализатор грамматики знает, когда ожидать оператор и когда выражение разрешено. Если вы преобразуете условное выражение в оператор, вы никогда не сможете использовать такое выражение как часть большего выражения!
Поскольку оператор if
является , а не выражением , он не возвращает значение (так как только выражения могут создавать значение), и поэтому результирующий байт-код не будет создайте значение в верхней части стека, которое будет использоваться окружающим кодом Python (нет c = if condition : ...
). if
операторы содержат условное выражение и suite , которые всегда должны состоять из большего количества операторов (существует такая вещь, как «выражение-выражение», которое позволяет вам просто поставить выражения в операторе (например, 1 + 1
в одной строке), и эти операторы могут «делать что-то», например, присваивать или возвращать из функции, но ничто из того, что они делают, не заставит if
вернуть что-либо.
Это отражено в определении узла AST для операторов if
:
stmt = [...]
| [...]
| If(expr test, stmt* body, stmt* orelse)
Таким образом, для узла If
, test
является единственным узлом выражения, а body
и orelse
оба состоят из ноль или более операторов. Часть orelse
будет содержать любые elif ...:
тесты как дополнительные If()
узлы или любой другой тип оператора для формирования безусловного else:
. С нулевым или большим количеством элементов вы не можете ожидать одного результата.
Так что это не уникально для CPython, это относится ко всем реализациям Python. Python грамматика не является деталью реализации.