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

a += b / 2

И

a += (b / 2)
5
Manngo 25 Сен 2018 в 21:54

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

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

6
Martijn Pieters 25 Сен 2018 в 19:05

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

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

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

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

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

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

a += (b / 2)
2
Willem Van Onsem 25 Сен 2018 в 19:24