Выполнение операций под надзором ast
Рассмотрим, как с помощью встроенного модуля ast
можно узнать порядок выполнения операций:
import ast
print(ast.dump(ast.parse('1 + 2 * 3 - 4', mode='eval'), indent=2))
Expression(
body=BinOp(
left=BinOp(
left=Constant(value=1),
op=Add(),
right=BinOp(
left=Constant(value=2),
op=Mult(),
right=Constant(value=3))),
op=Sub(),
right=Constant(value=4)))
Как можно видеть, наше выражение преобразовывается из обычной строки в дерево.
Затем интерпретатор вычисляет данное выражение с помощью поиска в глубину. Самые нижние (самые глубокие) операции вычисляются и сворачиваются в результат, который затем используется для вычисления верхних операций.
На примере 1 + 2 * 3 - 4
порядок вычислений будет таким:
2 * 3
BinOp(
left=Constant(value=2),
op=Mult(),
right=Constant(value=3))1 + (2 * 3)
BinOp(
left=Constant(value=1),
op=Add(),
right=BinOp(...))(1 + (2 * 3)) - 4
BinOp(
left=BinOp(...),
op=Sub(),
right=Constant(value=4))
Рассмотрим более сложный пример:
X & 127 / 2 ** 3 and Y or Z << 2 ^ 9
Expression(
body=BoolOp(
op=Or(),
values=[
BoolOp(
op=And(),
values=[
BinOp(
left=Name(id='X', ctx=Load()),
op=BitAnd(),
right=BinOp(
left=Constant(value=127),
op=Div(),
right=BinOp(
left=Constant(value=2),
op=Pow(),
right=Constant(value=3)))),
Name(id='Y', ctx=Load())]),
BinOp(
left=BinOp(
left=Name(id='Z', ctx=Load()),
op=LShift(),
right=Constant(value=2)),
op=BitXor(),
right=Constant(value=9))]))
Здесь уже можно видеть отличия: логические операции превращаются не в BinOp
, а в BoolOp
, который содержит уже список операндов.
Спускаемся в самую глубь:
2 ** 3
BinOp(
left=Constant(value=2),
op=Pow(),
right=Constant(value=3))127 / (2 ** 3)
BinOp(
left=Constant(value=127),
op=Div(),
right=BinOp(...))X & (127 / (2 ** 3))
BinOp(
left=Name(id='X', ctx=Load()),
op=BitAnd(),
right=BinOp(...))(X & (127 / (2 ** 3))) and Y
BoolOp(
op=And(),
values=[
BinOp(...),
Name(id='Y', ctx=Load())])Z << 2
BinOp(
left=Name(id='Z', ctx=Load()),
op=LShift(),
right=Constant(value=2))(Z << 2) ^ 9
BinOp(
left=BinOp(...),
op=BitXor(),
right=Constant(value=9))((X & (127 / (2 ** 3))) and Y) or ((Z << 2) ^ 9)
BoolOp(
op=Or(),
values=[
BoolOp(...),
BinOp(...))