0

I was shocked to find out that a += b behaves differently from a = a + b in my code, and I am able to reduce the issue to the following simple question:

Let's say I have a function g that depends on f (another function), x, y and lst (a list). Here I provide two versions of f, one using lst = lst + [y], the other using lst += [y]

def f1(x, y, lst=[]):
    lst.append(x)
    lst = lst + [y]
    return lst

def f2(x, y, lst=[]):
    lst.append(x)
    lst += [y]
    return lst

def g(f, x, y, lst=[]):
    return f(x, y, lst) + lst

However, I am getting different results:

print(g(f1, 1, 2, [3, 4]))
# [3, 4, 1, 2, 3, 4, 1]

print(g(f2, 1, 2, [3, 4]))
# [3, 4, 1, 2, 3, 4, 1, 2]

Can someone explain what is going on here?

Shaun Han
  • 2,676
  • 2
  • 9
  • 29
  • 1
    In general, beware that `+=` can be overloaded independently of `+`, so there is no reason for `+=` to behave coherently with `+`, besides the developers not doing weird stuff. – jthulhu Sep 25 '22 at 14:37
  • `f1` is creating new `lst` i.e. without referencing to old `lst` where as in `f2`, `lst` is referencing the same `lst` as in place operator is used which mutates the list. – GodWin1100 Sep 25 '22 at 14:38
  • Also beware of: ["Least Astonishment" and the Mutable Default Argument](https://stackoverflow.com/questions/1132941/least-astonishment-and-the-mutable-default-argument). – sj95126 Sep 25 '22 at 14:44

1 Answers1

0

If you want to get rid of this behavior then use .copy function.

def f1(x, y, lst):
    lst = lst.copy()
    lst.append(x)
    lst = lst + [y]
    return lst

def f2(x, y, lst):
    lst = lst.copy()
    lst.append(x)
    lst += [y]
    return lst

def g(f, x, y, lst=[]):
    return f(x, y, lst) + lst


print(g(f1, 1, 2, [3, 4]))
# [3, 4, 1, 2, 3, 4]

print(g(f2, 1, 2, [3, 4]))
# [3, 4, 1, 2, 3, 4]
codester_09
  • 5,622
  • 2
  • 5
  • 27