简短回答:+=是一个增广赋值,如果我们考虑到语法,它在语法树中的解析比一般的操作符(尤其是/运算符)要高。在
Python将+=视为“增强赋值”。如果我们检查Python grammar,我们会看到: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是一个{}的序列,其运算符为'*'、'@'、'/'、'%'、和{},所以这里我们最终“消费”了{}。因此,这意味着/在语法树中比+=节点低。在
因此,Python解析此表达式的方式是:
^{pr2}$