带有扩展分配的Python运算符优先级

时间:2018-09-25 18:54:27

标签: python operator-precedence augmented-assignment

似乎这个问题只针对Java回答,但是我想知道它在Python中是如何工作的。这些都一样吗?

a += b / 2

a += (b / 2)

2 个答案:

答案 0 :(得分:6)

是的,这些都是一样的。 Python的扩充分配不是表达式,它是一条语句,并且不使用表达式优先级规则。 +=不是运算符,而是扩展的赋值语句语法的一部分。

所以+= 右侧的所有都是表达式,而+=本身不是表达式,因此赋值将始终在最后处理。

并且因为(增强的)赋值不是表达式,所以它也不能产生用于周围表达式的值。没有(a += b) / 2,那是语法错误,当然也没有if (a += b / 2):或其他类似的恶作剧。

请参见reference documentation on Augmented assignment statements,其中指出语法为:

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

因此augop是语句语法的一部分,并且仅后面的部分是表达式(特别是expression_listyield_expression语法规则)。

此外,说明显示:

  

扩展赋值评估目标(与普通赋值语句不同,不能解包)和表达式列表,对两个操作数执行特定于赋值类型的二进制运算,并将结果赋值给原始目标。该目标仅评估一次。

因此,首先处理augtarget部分,然后处理表达式列表(或yield表达式),然后扩展分配应用运算符并分配回结果。

此外,表达式参考文档does include a precedence table,但是该表不包含赋值(经过扩展或其他方式),只是因为赋值不是表达式而是语句。

答案 1 :(得分:2)

简短答案+=增强的作业,如果我们考虑语法,则语法树中的语法要比语法中的语法高。运算符(尤其是/运算符)。

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_exprtest_listtest_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)