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