Приоритет оператора Python с расширенным присваиванием

Кажется, на этот вопрос ответили только для Java, но я хотел бы знать, как это работает в Python. Так это одно и то же?

a += b / 2

а также

a += (b / 2)

2 ответа

Решение

Да, это то же самое. Расширенное назначение Python не является выражением, оно является утверждением и не играет в правилах приоритета выражений. += не является оператором, а вместо этого является частью расширенного синтаксиса оператора присваивания.

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

А поскольку (расширенное) присваивание не является выражением, оно также не может создать значение для использования в окружающем выражении. Здесь нет (a += b) / 2, это было бы синтаксической ошибкой, и, конечно, нет if (a += b / 2): или другие подобные махинации.

См. Справочную документацию по расширенным операторам присваивания, в которой говорится:

augmented_assignment_stmt ::=  augtarget augop (expression_list | yield_expression)
augtarget                 ::=  identifier | attributeref | subscription | slicing
augop                     ::=  "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="
                           | ">>=" | "<<=" | "&=" | "^=" | "|="

Итак augop является частью синтаксиса оператора, и только следующая часть является выражением (в частности, либо expression_list или же yield_expression грамматическое правило).

Кроме того, объяснение показывает:

Расширенное назначение оценивает цель (которая, в отличие от обычных операторов назначения, не может быть распаковкой) и список выражений, выполняет двоичную операцию, специфичную для типа назначения для двух операндов, и присваивает результат исходной цели. Цель оценивается только один раз.

Итак augtarget сначала обрабатывается part, затем обрабатывается список выражений (или yield yield), а затем расширенное присваивание применяет оператор и присваивает результат обратно.

Кроме того, справочная документация по выражениям включает в себя таблицу приоритетов, но эта таблица не включает в себя присваивания (дополненные или иные) просто потому, что присваивания - это не выражения, а операторы.

Краткий ответ: += является расширенным назначением, и если мы примем грамматику во внимание, это синтаксически анализируется в синтаксическом дереве, чем операторы в целом (и, следовательно, / оператор в частности).

Питон видит += как "расширенное назначение". Если мы проверяем грамматику Python, мы видим:

augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
            '<<=' | '>>=' | '**=' | '//=')

Теперь грамматика также применяет правила приоритета при разборе. Если мы посмотрим на грамматику, которая связана с stmt ("утверждение") мы видим:

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
                     ('=' (yield_expr|testlist_star_expr))*)

Исчерпывающее объяснение всех других утверждений (например, del_statement) займет слишком много времени, но expr_stmt единственный, который приводит к augassign (а также augassign является единственной переменной, которая приводит к += маркер). Таким образом, мы можем игнорировать другие выражения.

Теперь, если мы "специализируем" выражение expr_stmt такой, что у него есть augassign в нем мы получаем производственное правило:

expr_stmt: testlist_star_expr augassign (yield_expr|testlist)

testlist_star_expr переменная, которая приводит к идентификатору (или нескольким идентификаторам в случае распаковки последовательности) и т. д.

Справа мы видим yield_exprили test_list, test_list может привести к выражению через запятую, с:

testlist: test (',' test)* [',']

это test позволяет писать троичные операторы, но это не обязательно:

test: or_test ['if' or_test 'else' test] | lambdef

Мы можем взять or_test переменная, которая используется для группировки выражений с or разделитель (снова необязательно), так как or имеет наивысший приоритет.

or_test: and_test ('or' and_test)*

Затем следует and_test что, как видно из названия, позволяет нам писать and операторы:

and_test: not_test ('and' not_test)*

затем следует not оператор (с not_test):

not_test: 'not' not_test | comparison

Мы можем иметь произвольное число notвпереди, но в итоге мы выберем comparison,

Если мы посмотрим на производственный маршрут для comparison, мы видим:

comparison: expr (comp_op expr)*

Таким образом, это позволяет компаратору цепочки, как x <= y < zДалее мы посмотрим на expr:

expr: xor_expr ('|' xor_expr)*
xor_expr: and_expr ('^' and_expr)*
and_expr: shift_expr ('&' shift_expr)*
shift_expr: arith_expr (('<<'|'>>') arith_expr)*
arith_expr: term (('+'|'-') term)*
term: factor (('*'|'@'|'/'|'%'|'//') factor)*

Так что это определяет правила приоритета, и мы видим, что | имеет приоритет над ^, который имеет приоритет над &и так далее, пока мы не увидим term это последовательность factorс операторами '*', '@', '/', '%', а также //и вот мы наконец "потребляем" наш *, Таким образом, это означает, что / ниже в дереве синтаксиса, чем += узел.

Следовательно, Python анализирует это выражение так:

a += (b / 2)
Другие вопросы по тегам