Python operator precedence with augmented assignment including sequence

179 Views Asked by At

Following up my previous question I have the following one. Are these the same in Python?

a += b[1] / 2

and

a += (b[1] / 2)

Providing that:

  • a has already been defined earlier as float
  • b is a list of tuples
  • b[1] is a tuple with a single element

Similarly I would be interested to learn as well the behavior if:

  • a has already been defined earlier as float
  • b is a list of floats
1

There are 1 best solutions below

0
On BEST ANSWER

The rules of how Python parses expressions are defined in the Python grammar. Note that the types are irrelevant. In fact Python is dynamically types, so that means that at the time an expression is parsed and analyzed, the types of the variables is unknown. In fact a variable have different values (with different types) through the process, and a line can be evaluated multiple times, with the variables each time carrying a value of a different type.

If we take a look at the grammar, we see:

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)*
factor: ('+'|'-'|'~') factor | power
power: atom_expr ['**' factor]
atom_expr: ['await'] atom trailer*
atom: ('(' [yield_expr|testlist_comp] ')' |
       '[' [testlist_comp] ']' |
       '{' [dictorsetmaker] '}' |
       NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')
testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME

The "subscription" (the [1] in b[1] is thus defined in a production rule of trailer, and if we look at the grammar, this can only be the product of a factor, so that means that the / operator takes precedence over the subscription.

So that means that:

a += b[1] / 2

is equivalent to:

a += ((b[1]) / 2)

Note that since Python is dynamically typed, the parsing (and analyzing) step will not give any guarantees that the expression is sensical. For example a tuple can not be devided by two. So this will result in a TypeError:

>>> (2.0, 4.0) / 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'tuple' and 'int'

For a numpy array however, this makes sense:

>>> from numpy import array
>>> array([2.0, 4.0])/2
array([1., 2.])