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.
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.
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.
*=
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
.*
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).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.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