Приоритет оператора Python с расширенным присваиванием - PullRequest
0 голосов
/ 25 сентября 2018

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

a += b / 2

и

a += (b / 2)

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

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

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

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

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

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

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

Теперь, если мы "специализируем" выражение 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)*

затем следует оператор notnot_test):

not_test: 'not' not_test | comparison

Мы можем иметь произвольное число not s впереди, но в конечном итогемы выберем 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 s с операторами '*', '@', '/', '%'и //, поэтому здесь мы, наконец, «потребляем» наш *.Таким образом, это означает, что / ниже в синтаксическом дереве, чем узел +=.

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

a += (b / 2)
0 голосов
/ 25 сентября 2018

Да, это то же самое.Расширенное назначение 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, затем обрабатывается список выражений (или выражение yield), а затем расширенное присваивание применяет оператор и присваивает обратнорезультат.

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

...