I'm new to Python and I'm still learning. I've learned the concept of left-sided binding when using operators (and it was taught that only exponentiation uses RIGHT-SIDED BINDING). It was also taught to me that, both * and / have equal priority and Binding of the operator determines the order of computation performed by some operators with equal priority, put side by side in one expression.
But now when teaching compound assignment operators, they used the following example
a = 6
b = 3
a /= 2 * b
print(a)
The answer given is 1.0.
The explanation they have given is as follows.
2 * b = 6
a = 6 → 6 / 6 = 1.0
My question is, isn't a/=2*b is the same thing as a=a/2*b. So when considering a=a/2*b shouldn't the division be considered first becuase of the left sided binding and then the multiplication later.
a = 6 → 6/2 = 3.0
3.0 * b = 9.0.
So shouldn't 9.0 be the answer. Please explain this to me.
The statement a /= 2 * b is equivalent to a /= (2 * b), not (a /= 2) * b, which doesn't make sense in Python.
If you did interpret it as (a /= 2) * b, then it would expand to (a = a / 2) * b, not a = (a / 2) * b. This is not allowed in Python because a = a / 2 is not an expression and it does not produce a value which could be multiplied by b.
The answer is that the assignment operator _ = _, and the augmented assignment operators like _ /= _, have a lower precedence than other operators (like _ * _ and _ / _), and they are "right-associative" syntactically so that a = b = c assigns the result c to both a and b; however, it would not be correct to write that this is equivalent to a = (b = c), since this does not make sense in Python for the above reason. Still, _ ** _ is not the only right-associative operator in Python: another one is the ternary operator _ if _ else _, where an expression a if b else c if d else e is equivalent to a if b else (c if d else e), not (a if b else c) if d else e.
Python follows the usual order of operations used in math, where exponents take priority over multiplication/division and they, in turn, over addition/subtraction. Compound operators are the last in this order. So in your example, 2*b is evaluated first and returns 6. Then a/=6 is evaluated and returns 1.
Related
The order of operations in my code seems off...
numbers=[7, 6, 4]
result = 1
for num in numbers:
result *= num - 3
print(result)
In this code, I would expect the following to occur...
result=1
result = 1 * 7 - 3 = 7 - 3 = 4
result = 4 * 6 - 3 = 24 - 3 = 21
result = 21 * 4 - 3 = 84 - 3 = 81
HOWEVER, running the program outputs
result = 1
result = 1 * 7 - 3 = 1 * 4 = 4
result = 4 * 6 - 3 = 4 * 3 = 12
result = 12 * 4 - 3 = 12 * 1 = 12
Why with the *= operator is the order of operations altered?
My understanding is it does not have any special properties it merely saves space instead of writing:
result = result * num - 3
we get
result *= num - 3
and for some reason.. (result = result * num - 3) != (result *= num - 3)
Why with the *= operator is the order of operations altered?
The *= is not an operator, it's delimiter. Check the '2. Lexical analysis' of 'The Python Language Reference':
The following tokens are operators:
+ - * ** / // % #
<< >> & | ^ ~ :=
< > <= >= == !=
The following tokens serve as delimiters in the grammar:
( ) [ ] { }
, : . ; # = ->
+= -= *= /= //= %= #=
&= |= ^= >>= <<= **=
The period can also occur in floating-point and imaginary literals. A
sequence of three periods has a special meaning as an ellipsis
literal. The second half of the list, the augmented assignment
operators, serve lexically as delimiters, but also perform an
operation.
Moreover, in your code you have the, augmented assignment statement, as per '7.2.1. Augmented assignment statements':
Augmented assignment is the combination, in a single statement, of a binary operation and an assignment statement:
[...]
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.
An augmented assignment expression like x += 1 can be rewritten as x =
x + 1 to achieve a similar, but not exactly equal effect. In the
augmented version, x is only evaluated once. Also, when possible, the
actual operation is performed in-place, meaning that rather than
creating a new object and assigning that to the target, the old object
is modified instead.
Unlike normal assignments, augmented assignments evaluate the
left-hand side before evaluating the right-hand side. For example,
a[i] += f(x) first looks-up a[i], then it evaluates f(x) and performs
the addition, and lastly, it writes the result back to a[i].
The '6.16. Evaluation order' says:
Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.
You can also check the '6.17. Operator precedence' chapter, but it's not about the statements.
The expression on the right hand side of the *= is evaluated first.
7 - 3 => 4 which multiplied by 1 is 4.
6 - 3 => 3 which multiplied by 4 is 12.
4 - 3 => 1 which multiplied by 12 is 12.
To achieve what you are expecting:
numbers = [7, 6, 4]
result = 1
for num in numbers:
result = result * num - 3
print(result)
numbers=[7, 6, 4]
result = 1
for num in numbers:
result *= num-3
print(result)
The *= operator is a compound assignment operator, which means that it combines the assignment operator = with another operator
https://www.educative.io/answers/what-are-the-compound-assignment-identity-operators-in-python
numbers=[7, 6, 4]
result = 1
for num in numbers:
result = result*num-3
print(result)
the *= means that the * will be used between what's before it and what's after so you need to get result_2 in this example to get what you want :
numbers = [7,6,4]
result = 1
result_2 = 1
for number in numbers:
result *= number -3
result_2 = result_2 * number -3
print(result, result_2)
I was playing around with few basic operations in Python 3 and came across this
Code 1:
a = 6
b = 3
a = a / 2 * b
print(a)
Output is 9.0
In one of the trainings I have seen that
a = a / 2
can be written as
a /= 2
So I re-wrote my above code as below
Code 2:
a = 6
b = 3
a /= 2 * b
print(a)
But now the output is 1.0.
I was expecting 9.0 as output. Can someone help me understand why code behaves this way?
In the case of a /= 2 * b, you saying that a will be divided by expression after /=.
In other words, your expression could be rewritten as a = a / (2 * b) where a = 6, b = 3
in
a /= 2 * b
the 2 * b is carried out first so if b == 3 it can be rewritten as:
a /= 6
That's because they perform operations in different order.
The first of block of code divides a (6) by 2 and then multiplies that result by b (3)
E.g. (6 / 2) * 3 = 9
However the second block of code does the following:
6 / (2 * 3) = 1
Note, that
a /= 2 * b
is basically
a = a / (2 * b)
The previous code is different. It's not like the above (look at the parentheses)
a = a / 2 * b
This is different than
a = a / (2 * b)
Because the first code interpret it as division and then multiply, while the second code interpret it as multiply (bottom) and then division.
as you can see in the documentatiopn on operator precedence * and / have the same precedence. two operations with the same precedence are executed from left to right:
Operators in the same box group left to right
so your first example is evaluated as
(a / 2) * b
the second as
a / (2 * b)
regarding your comment
a = a / 2 and a /= 2 are always equivalent, right?
for the built-in python numbers you are right.
for your own classes you can make the operations differ. if a is an insance of a custom class a/x will call __truediv__(self, other) while a/=x will call __itruediv__(self, other) as described in the data model.
I'm surprised none of the other answers mention this, but the reason doesn't have anything to do with math, order of operations or implicit parentheses.
x /= y is just another way of saying x.__itruediv__(y). Your second example is not equivalent to your first example, because parameters are evaluated before being passed in to a function call. So, a /= 2 * b is equivalent to a.__itruediv__(2 * b), and naturally, the expression 2 * b must be evaluated before being passed in to __itruediv__.
We can easily find:
a=7
b=8
c=a|b
Then c comes out to be: 15
Now can we find a if c is given?
For example:
b=8
c=15
c=a|b
Find a?
And also if x=2<<1 is given, then we can get x=4. But if 4=y<<1 is given Can we get y?
To begin with, these are just my observations and I have no sources to back them up. There are better ways, but the Wikipedia pages were really long and confusing so I hacked together this method.
Yes, you can, but you need more context (other equations to solve in reference to) and a lot more parsing. This is the method I came up with for doing this, but there are better ways to approach this problem. This was just conceptually easier for me.
Numbers
You can't just put an integer into an equation and have it work. Bitwise operators refer only refer to booleans, we just treat them as if they are meant for integers. In order to simplify an equation, we have to look at it as an array of booleans.
Taking for example an unsigned 8 bit integer:
a = 0b10111001
Now becomes:
a = {1, 0, 1, 1, 1, 0, 0, 1}
Parsing
Once you can get your equations to just booleans, then you can apply the actual bitwise operators to simple 1s and 0s. But you can take it one step further now, at this all bitwise equations can be written in terms of just AND, OR, and NOT. Addition, subtraction and multiplication can also be represented this way, but you need to manually write out the steps taken.
A ^ B = ~( ( A & B ) | ( (~A) & (~B) ) )
This includes bitshifts, but instead of expanding to other bitwise operators, they act as an assignment.
A = 0b10111001
B = 0b10100110
C = (A >> 2) ^ B
This then expands to 8 equations, one for each bit.
C[0] = A[2] ^ B[0]
C[1] = A[3] ^ B[1]
C[2] = A[4] ^ B[2]
C[3] = A[5] ^ B[3]
C[4] = A[6] ^ B[4]
C[5] = A[7] ^ B[5]
C[6] = 0 ^ B[6]
C[7] = 0 ^ B[7]
C[6] and C[7] can then be reduced to just B[6] and B[7] respectively.
Algebra
Now that you have an equation consisting of only AND, OR, and NOT, you can represent them using traditional algebra. In this step, they are no longer treated as bits, but instead as real numbers which just happen to be 0 or 1.
A | B => A + B - AB
A & B => AB
~A => 1 - A
Note that when plugging in 1 and 0, all of these remain true.
For this example, I will be using the Majority function as an example. It's job is to take in three bits and return 1 if there are more 1s than 0s.
It is defined as:
f(a, b, c) = ((a & b) | (a & c) | (b & c))
which becomes
f(a, b, c) = (ab + ac - (ab * ac)) + bc - (ab + ac - (ab * ac) * bc
f(a, b, c) = ab + ac + bc - a2bc - ab2c - abc2 + a2b2c2
And now that you have this information, you can easily combine it with your other equations using standard algebra in order to get a solution. Any non 1 or 0 solution is extraneous.
A solution (if it exists) of such equation can be considered "unique" provided that you allow three states for each bit:
bit is 0
bit is 1
does not matter X
E.g. 7 | 00001XXX(binary) = 15
Of course, such result cannot be converted to decimal.
For some operations it may be necessary to specify the bit width.
For your particular cases, the answer is no, you cannot solve or 'undo' the OR-operation (|) and shifting left or right (<<, >>) since in both cases information is lost by applying the operation. For example, 8|7=15 and 12|7=15, thus given the 7 and 15 it is not possible to obtain a unique solution.
An exception is the XOR operation, for which does hold that when a^b=c, then b^c=a and a^c=b.
you can find an a that solves the equation, but it will not be unique. assume b=c=1 then a=0 and a=1 are solutions. for c=1, b=0 there will be no solution. this is valid for all the bits in the numbers you consider. if the equation is solvable a=c will be (one of the) solution(s).
and left-shifting an integer will always result in an even integer (the least-significant bit is zero). so this only works for even itegers. in that case you can invert the operation by applying a right-shift (>>).
I am using the sympy library for python3, and I am handling equations, such as the following one:
a, b = symbols('a b', positive = True)
my_equation = Eq((2 * a + b) * (a - b) / 2, 0)
my_equations gets printed exactly as I have defined it ((2 * a + b) * (a - b) / 2 == 0, that is), and I am unable to reduce it even using simplify or similar functions.
What I am trying to achieve is simplifying the nonzero factors from the equation (2 * a + b and 1 / 2); ideally, I'd want to be able to simplify a - b as well, if I am sure that a != b.
Is there any way I can reach this goal?
The point is that simplify() is not capable (yet) of complex reasoning about assumptions. I tested it on Wolfram Mathematica's simplify, and it works. It looks like it's a missing feature in SymPy.
Anyway, I propose a function to do what you're looking for.
Define this function:
def simplify_eq_with_assumptions(eq):
assert eq.rhs == 0 # assert that right-hand side is zero
assert type(eq.lhs) == Mul # assert that left-hand side is a multipl.
newargs = [] # define a list of new multiplication factors.
for arg in eq.lhs.args:
if arg.is_positive:
continue # arg is positive, let's skip it.
newargs.append(arg)
# rebuild the equality with the new arguments:
return Eq(eq.lhs.func(*newargs), 0)
Now you can call:
In [5]: simplify_eq_with_assumptions(my_equation)
Out[5]: a - b = 0
You can easily adapt this function to your needs. Hopefully, in some future version of SymPy it will be sufficient to call simplify.
This question already has answers here:
What is this operator *= -1
(2 answers)
Closed 9 years ago.
For example in this code:
def product(list):
p =1
for i in list:
p *= i
return p
I found this code, but I need to be able to explain each and every part of it.
It's shorthand for
p = p * i
It's analogous to the more frequently encountered p += i
Taken from the first result in google:
Multiply AND assignment operator, It multiplies right operand with the left operand and assign the result to left operand
*= is the same as saying p = p * i.
This link contains a list of all the operators in their various, wonderful combinations.
Example
A pseudo-code explanation of your code is as follows:
assume list := {4, 6, 5, 3, 5, 1}
p := 1.
for(each number in list)
p = the current value of p * the current number.
// So: 1 * 4, 4 * 6, 24 * 5, 120 * 3...
return p.
Usually p *= i is the same as p = p * i.
Sometimes it can be different, and I think the explanations already posted aren't clear enough for that, so:
It can be different when p is a mutable object. In that case the in-place *= may modify the original object instead of creating a new one. Compare what happens to q in each of these:
>>> p = q = [2]
>>> p *= 5
>>> p
[2, 2, 2, 2, 2]
>>> q
[2, 2, 2, 2, 2]
>>> p = q = [2]
>>> p = p * 5
>>> p
[2, 2, 2, 2, 2]
>>> q
[2]
If can also be different when p is a complex expression with side effects as the in-place version only evaluates sub-expressions once. So for example:
aList[randint(0, 5)] *= 3
is not the same as:
aList[randint(0, 5)] = aList[randint(0, 5)] * 3
It's not exactly the same as p = p * i:
>>> class A(int):
... def __imul__(self, item):
... print '__imul__ is running!'
...
... def __mul__(self, item):
... print '__mul__ is running!'
>>> mynumber = A(10)
>>> mynumber *= 5
__imul__ is running!
>>> mynumber = A(10)
>>> mynumber * 5
__mul__ is running!
However the output is mostly the same, so you should probably treat it so
The idea behind the operator a *= b is to mean the same as a = a * b. In most cases (as in yours) it will do exactly this, so it multiplies a variable with a value and stores the result in the variable again.
The notation using *= might be faster (depending on the classes involved), and it is, in any case, the clearer version, so it should be favored. Its main advantage shows if the variable a is itself already a complex expression like myGiantValueField[f(42)].getValue()[3]:
myGiantValueField[f(42)].getValue()[3] = myGiantValueField[f(42)].getValue()[3] * 3
is certainly less readable and due to code doubling more prone to fixing-errors than
myGiantValueField[f(42)].getValue()[3] *= 3
In general, though, the operator *= calls the method __imul__() of the variable a and hands over the argument b, so it means exactly the same as a.__imul__(b) (which isn't as intuitive).
Why could there be a difference between a = a * b and a *= b? Three reasons come two mind at once, but there might be more.
A class could implement only the *= operator (so a * b could be undefined although a *= b exists) due to performance aspects. Multiplying a very large value (e. g. a giant matrix) with a number is sometimes better done in-place to avoid having to allocate memory for the result (which might at once after computation be copied into the original variable by the assignment). That a = a * b is internally sth like tmp = a * b and a = tmp.
A class might find its use unintuitive using the direct multiplication, hence it could leave the * operator unimplemented. An example might be a class representing the volume of the computer speaker. Doubling the volume might make sense (volumeKnob *= 2) whereas computing it without using (assigning) it is not recommended (x = volumeKnob * 2? ← makes no sense as it does nothing).
If the type of the result of the multiplication differs from the type of a, I would not expect or recommend implementing the *= operator as it would be misleading. An example might be if a and b are vectors whose multiplication result would be a matrix (or a number). The name __imul__ already suggests that it is meant for being applied iteratively, i. e. more than once. But if a's type changed, this would be problematic.