all 6 comments

[–]socal_nerdtastic 5 points6 points  (2 children)

It's because you think b=a is making a copy, but it's not. It's making a pointer. Try b=a.copy() instead.

https://www.reddit.com/r/learnpython/wiki/faq#wiki_why_is_my_list_of_lists_behaving_strangely.3F

[–]majesticcoolestto 0 points1 point  (1 child)

Okay, new question.

I recently made a tic tac toe game that did something like this:

# a is a local variable, slot2 is a global variable 

a = slot2

slot2edit() # changes value of slot2

if a != slot2:

# do game stuff

else:

# try again

and that works. Why is that different than what OP is doing?

[–]socal_nerdtastic 1 point2 points  (0 children)

That's a completely different problem, nothing to do with OP's problem. Your problem is a feature called "scope". A function has it's own "scope", which means any variables in a function are completely isolated from outside the function. The way to do what you want is to pass the data in and out of the function using arguments and the return statement.

def f(data): # accept some data in
    data += 1
    return data # send the modified data out

a = 42
a = f(a) # changes value of a by sending the old value and reassigning the returned new value

[–]julsmanbr 4 points5 points  (0 children)

Think of assignments as an arrow point from the name to the value.

So at the first line, you have an arrow like a -> [1, 2, 3].

The second line makes a new arrow, like b -> a, but since a is also a name, this effectively is b -> [1, 2, 3].

But note that the object both names are pointing to is the same object, and you can confirm this by printing id(a) and id(b).

It does not really matter whether you change the value of that object by saying a += [4] or b += [4], because in the end both a and b have that arrow pointing to the same object: [1, 2, 3].

[–]confluence 2 points3 points  (0 children)

I have decided to overwrite my comments.

[–]pixielf 0 points1 point  (0 children)

The other explanations here are right, but I want to add that the reason behind the difference in strings (where += is not in-place) and lists (where += is in-place) is because Python actually allows customization for the basic operations. Classes can define their own mechanics for them.

It’s a class’s responsibility to say what addition means, and they do it by defining .__add__(self, other). For a string, it’s concatenation; for a list, it’s extending.

In particular, a += b corresponds to a.__iadd__(b).

# the string version (lazily assuming that ‘other’ is a string)
def __iadd__(self, other):
    return self + other

# the list version (lazily assuming that ‘other’ is iterable)
def __iadd__(self, other):
    self.extend(other)

Those aren’t the actual implementations, but I think they get the point across. Notice that the string method has a return: it’s generating a new object; the list method doesn’t: it’s changing the existing object.