似乎这个问题只针对 Java 回答,但我想知道它在 Python 中是如何工作的。那么这些是一样的吗?
a += b / 2
和
a += (b / 2)
似乎这个问题只针对 Java 回答,但我想知道它在 Python 中是如何工作的。那么这些是一样的吗?
a += b / 2
和
a += (b / 2)
是的,这些都是一样的。Python 的扩充赋值不是一个表达式,它是一个语句,并且不在表达式优先规则中起作用。+=
不是运算符,而是增强赋值语句语法的一部分。
所以右边的+=
所有东西都是一个表达式,但+=
它本身不是,所以赋值总是最后处理。
并且因为(增强的)赋值不是表达式,它也不能产生在周围表达式中使用的值。没有(a += b) / 2
,那将是一个语法错误,当然也没有if (a += b / 2):
或其他类似的恶作剧。
请参阅有关Augmented assignment statements的参考文档,其中指出语法为:
augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression) augtarget ::= identifier | attributeref | subscription | slicing augop ::= "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" | ">>=" | "<<=" | "&=" | "^=" | "|="
所以augop
is 是语句语法的一部分,只有后面的部分是表达式(具体来说,要么是 a 要么是expression_list
语法yield_expression
规则)。
此外,解释表明:
扩充赋值计算目标(与普通赋值语句不同,不能解包)和表达式列表,对两个操作数执行特定于赋值类型的二元运算,并将结果分配给原始目标。目标只评估一次。
因此,augtarget
首先处理部分,然后处理表达式列表(或屈服表达式),然后扩展赋值应用运算符并分配回结果。
此外,表达式参考文档确实包含一个优先表,但该表不包含赋值(增强或其他),仅仅是因为赋值不是表达式而是语句。
简短的回答:+=
是一个扩充的赋值,如果我们考虑到语法,它在语法树中的解析比一般的运算符(因此/
特别是运算符)更高。
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
是唯一导致 an 的语句(augassign
并且是唯一导致令牌augassign
的变量)。+=
所以我们可以忽略其他表达式。
现在,如果我们“特化”这样的表达式expr_stmt
,使其具有一个augassign
,我们检索生产规则:
expr_stmt: testlist_star_expr augassign (yield_expr|testlist)
这testlist_star_expr
是一个导致标识符(或在序列解包的情况下为多个标识符)等的变量。
在右边yield_expr
,我们看到 a 或 a test_list
。Atest_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)*
所以这定义了优先规则,我们看到 that|
优先于^
, that 优先于&
,依此类推,直到我们看到 aterm
是factor
s 的序列,其中包含 , , , 和 的运算符'*'
,'@'
所以'/'
在'%'
这里//
我们最终“消费”了我们的*
。因此,这意味着/
语法树中的 比+=
节点低。
因此 Python 解析这个表达式的方式是:
a += (b / 2)