Python 具有增强赋值的运算符优先级
Python operator precedence with augmented assignment
这个问题似乎只回答了 Java,但我想知道它在 Python 中是如何工作的。那么这些是一样的吗?
a += b / 2
和
a += (b / 2)
是的,它们是一样的。 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_list
或yield_expression
语法规则)。
此外,解释显示:
An augmented assignment evaluates the target (which, unlike normal assignment statements, cannot be an unpacking) and the expression list, performs the binary operation specific to the type of assignment on the two operands, and assigns the result to the original target. The target is only evaluated once.
因此首先处理 augtarget
部分,然后处理表达式列表(或 yield 表达式),然后扩充赋值应用运算符并将结果赋值回来。
此外,表达式参考文档 does include a precedence table,但 table 不包括赋值(增强或其他),仅仅是因为赋值不是表达式而是语句。
简答:+=
是一个扩充赋值,如果我们考虑语法,这会被解析在语法树中高于一般运算符(因此特别是 /
运算符)。
Python 将 +=
视为“ 扩充赋值 ”。如果我们检查 Python grammar,我们会看到:
augassign: (<b>'+='</b> | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
'<<=' | '>>=' | '**=' | '//=')
现在语法在解析时也强制执行优先级规则。如果我们查看与 stmt
("statement") 相关的语法,我们会看到:
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
是导致 +=
标记的唯一变量)。所以我们可以忽略其他表达式。
现在,如果我们 "specialize" 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
是一个包含 '*'
、'@'
、'/'
、'%'
和 //
运算符的 factor
序列,所以这里我们最终 "consume"我们的*
。因此,这意味着 /
在语法树中的位置低于 +=
节点。
因此 Python 解析此表达式的方式是:
a += (b / 2)
这个问题似乎只回答了 Java,但我想知道它在 Python 中是如何工作的。那么这些是一样的吗?
a += b / 2
和
a += (b / 2)
是的,它们是一样的。 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_list
或yield_expression
语法规则)。
此外,解释显示:
An augmented assignment evaluates the target (which, unlike normal assignment statements, cannot be an unpacking) and the expression list, performs the binary operation specific to the type of assignment on the two operands, and assigns the result to the original target. The target is only evaluated once.
因此首先处理 augtarget
部分,然后处理表达式列表(或 yield 表达式),然后扩充赋值应用运算符并将结果赋值回来。
此外,表达式参考文档 does include a precedence table,但 table 不包括赋值(增强或其他),仅仅是因为赋值不是表达式而是语句。
简答:+=
是一个扩充赋值,如果我们考虑语法,这会被解析在语法树中高于一般运算符(因此特别是 /
运算符)。
Python 将 +=
视为“ 扩充赋值 ”。如果我们检查 Python grammar,我们会看到:
augassign: (<b>'+='</b> | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=')
现在语法在解析时也强制执行优先级规则。如果我们查看与 stmt
("statement") 相关的语法,我们会看到:
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
是导致 +=
标记的唯一变量)。所以我们可以忽略其他表达式。
现在,如果我们 "specialize" 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
是一个包含 '*'
、'@'
、'/'
、'%'
和 //
运算符的 factor
序列,所以这里我们最终 "consume"我们的*
。因此,这意味着 /
在语法树中的位置低于 +=
节点。
因此 Python 解析此表达式的方式是:
a += (b / 2)