0

Although both functions are logically doing the same thing i.e. doubling the list by itself, why does one function modify the original list and the other doesn't? The only difference visible in the code is that func2() uses short-hand notation for doubling while func1() doesn't.

Aren't my_list *= 2 and my_list = my_list * 2 equivalent?

Approach 1:

def func1(my_list):
    my_list = my_list * 2

x = [1, 2, 3]
func1(x)
print(x)

Output:

[1, 2, 3]

Approach 2:

def func2(my_list):
    my_list *= 2

x = [1, 2, 3]
func2(x)
print(x)

Output:

[1, 2, 3, 1, 2, 3]
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
sshrey47
  • 9
  • 4
  • No, they are not equivalent. `*=` modifies the list in place. `*` returns a new list. – khelwood Apr 11 '21 at 08:18
  • See https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types - "`s *= n` **updates *s*** with its contents repeated *n* times". – jonrsharpe Apr 11 '21 at 08:19
  • @johnrsharpe In python they have implemented using operator overloading ? – Amit Vikram Singh Apr 11 '21 at 08:22
  • 1
    @AmitVikramSingh what do you mean? They're two different magic methods, `__mul__` and `__imul__`. – jonrsharpe Apr 11 '21 at 08:24
  • So when we do `my_list *= 2` it's basically a call to __imul__, which is achieved by overloading the operator `*=`, this I wanted to know. – Amit Vikram Singh Apr 11 '21 at 08:27
  • Related for `+=`: https://stackoverflow.com/q/58866870/3001761 – jonrsharpe Apr 11 '21 at 08:33
  • Does this answer your question? [How are Python in-place operator functions different than the standard operator functions?](https://stackoverflow.com/questions/4772987/how-are-python-in-place-operator-functions-different-than-the-standard-operator) – Tomerikoo Apr 11 '21 at 09:09

1 Answers1

4

Per the docs *= (__imul__) is only natively* available on mutable sequences, including list (emphasis mine):

Operation Result Notes
s *= n updates s with its contents repeated n times (6)

whereas * (__mul__) is available on all sequences:

Operation Result Notes
s * n or n * s equivalent to adding s to itself n times (2)(7)

For your two examples:

  • my_list = my_list * 2 is equivalent to my_list = my_list + my_list, which creates a new, longer list and assigns it back to the same name
  • my_list *= 2 is like my_list.extend(my_list), it's an in-place operation

This is also mentioned in the data model documentation for augmented assignment:

These methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self).

These augmented assignment behaviours can be surprising, one's even called out in the programming FAQ.

* as khelwood points out in the comments, *= will fall back to using __mul__ where __imul__ isn't implemented, so for immutable sequences foo *= bar and foo = foo * bar do the same thing.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • 1
    `__imul__` may not be available on immutable sequences, but `*=` is. It falls back on `__mul__`, so it has different behaviour. – khelwood Apr 11 '21 at 10:35