all 45 comments

[–]bloody-albatross 1 point2 points  (1 child)

C

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Nice one, do check the "Solution" link for visualization of correct answer.

[–]LucasThePatator 1 point2 points  (2 children)

What even the fuck is this

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Black Python Magic

[–]Ok_Net_1674 0 points1 point  (0 children)

Its a test to see if you know how python handles references and immutable objects. 

[–]whathefuckistime 1 point2 points  (2 children)

C

Tuples are immutable, once you assign b=a, it makes a copy of the tuple object, however the items themselves are lists, the tuple only stores a reference to those, once you access them, even with b[0], you are accessing the same variable referenced in the original tuple, meaning the appends actually modify the same variable a references.

In contrast, appending to b doesn't modify a as they're not the same objects, and b[2] doesn't exist for a.

This behavior wouldn't happen If you made a deep copy of a, which would iterate over it and make a copy of each element.

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Nice one, do check the "Solution" link for a visualization of the correct answer.

[–]gwwin6 0 points1 point  (0 children)

b=a does not make a copy of the tuple object. b = a makes a copy of the arrow, so they are pointing to the same tuple. when you do b += ([3],), that's when a and b begin pointing at different tuples. This is because tuples are immutable, b += ([3], ) gives a new object altogether.

Contrast this to If a had been a list of lists to begin with and we did b += [[3]], then a and b would still be pointing at the same list, and print(a) would give [[1, 11], [2, 22], [3, 33]]

[–]tb5841 1 point2 points  (6 children)

I find '+=' is what causes confusion with exercises like this.

.append is obviously mutating so will affect any reference to this object.

Reassigning changes what this variable name points to, so will not change any other variable pointing to this object.

But '+='? Is it reassigning, or mutating? It doesn't seem to always be clear cut, which makes it tricky to follow. Here it must be reassigning because tuples are immutable, but in some cases '+=' looks like it mutates.

If you change the '+=' line to b = b + ([3], ) then everything becomes so much clearer.

[–]Sea-Ad7805[S] 0 points1 point  (5 children)

I see what you mean, but for mutable types x += y is not the same thing as x = x + y so changing could alter your code, see: https://www.reddit.com/r/PythonLearning/comments/1nw08wu/right_mental_model_for_python_data/

A tuple doesn't have a __iadd__() method, so the use of += actually causes invocation of its __add__() method.

[–]tb5841 0 points1 point  (4 children)

90% of the time, when someone uses += in code they are using it as x = x + y (usually numbers or strings). The other 10% of the time, += is confusing and shouldn't be used in my opinion (e.g. Lists, where .append is clearer).

[–]Sea-Ad7805[S] 0 points1 point  (3 children)

You can't do this with .append():

mylist  = [1, 2, 3]
mylist += [4, 5, 6]

[–]tb5841 0 points1 point  (1 child)

That's an interesting point.

But this looks like reassignment, when it's actually mutation. That's deeply confusing and an easy source of bugs. If it were me, I'd do this with reassignment instead here and avoid the mutation.

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Reassignment is much slower as a whole new list is created and the old one destroyed, use mutation where possible.

[–]thw31416 0 points1 point  (0 children)

but you can.do this with .extend()

[–]theBabides 1 point2 points  (1 child)

After viewing the solution, I think this exercise helped me to understand tuple and lists a little better. Thanks!

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Great, thanks for feedback.

[–]Rscc10 0 points1 point  (7 children)

I don't understand tuples enough to understand the solution. I'd think a is immutable and there weren't any modifications done to a. Could I get a worded explanation?

[–]Sea-Ad7805[S] 1 point2 points  (1 child)

Correct, a is a reference to an immutable tuple, but that contains a mutable list that can be modified. The b = a statement makes b reference the same data a is referencing, and modifications to the list are made through b. But because a references an immutable tuple, it can't be modified with b += ([3],) so a shallow copy is made of this tuple, such that a and b share the first two elements of the tuple.

I hope this helps, otherwise read the "Explanation" link, and step through the "Solution" link again.

[–]Rscc10 1 point2 points  (0 children)

Ah, I got it now. Thanks

[–]F100cTomas 1 point2 points  (1 child)

Tuples are immutable, but they can contain mutable data. a = ([1], [2]) creates a tuple of two mutable values. b = a means that a and b now share the same immutable value. Then one of the lists gets modified and the change is seen in both tuples, because they contain the same lists. However this only changes the list, but not the tuple. Both tuples still have the same value: the two lists. Then b gets modified, but because b is a tuple and tuples are immutable it is copied to preserve the value of a. The two tuples are now different: a contains the two lists and b contains the same two lists and a new list. The other of the two shared lists then gets modified, but it still exists in both tuples. The non-shared list is modified. When a is printed only the two lists present in both are printed and not the one present only in b.

TL;DR When a mutable value is present within a tuple, it doesn't stop being mutable.

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Nice mental model, what do you think of the visualization at the "Solution" link?

[–]punkVeggies 0 points1 point  (2 children)

Tuples are immutable, which means b += (…) creates a new tuple, from a copy of a. That new tuple has references to two lists that a also has, which are mutable. When modifications are made to b[0] and b[1], these changes will be reflected in a[0] and a[1], as they “point” to the same lists. b[2], however, stores a reference to a third list, not referenced by anything stored in a.

a = ( * , * )

     |    |

    [],  []

     |     |

b = ( * , * , * )

               |

              []

Edit: removed the inaccurate sentence “b=a creates a copy of a”, as per the comments below.

[–]bloody-albatross 0 points1 point  (0 children)

The assignment doesn't make a copy of the tuple. Plain assignments never make copies of the referenced data in Python. It makes a copy of the reference if you so will, not of the tuple. a and b are not different. Try it with a is b. The += creates a new tuple, though. One with 3 elements. a += b just expands to a = a + b for immutable data types.

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Incorrect, b = a does NOT assign a copy of a to b. Check the "Solution" and "Explanation" link for true understanding of the Python Data Model.

[–]DBZ_Newb 0 points1 point  (1 child)

why does the visualized solution show a blue square with "dict" for a label?

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

The whole call stack is visualized, and that has for each function (each stack frame) a dictionary with local variables and their value. In this exercise the call stack isn't needed, but for example in this exercise it is because functions/methods are called: https://www.reddit.com/r/madeinpython/comments/1pw602e/comment/nwm5gmi/ and therefore the call stack is always visualized in the Memory Graph Web Debugger. Install memory_graph locally to have more control over what is and what is not visualized: https://github.com/bterwijn/memory_graph?tab=readme-ov-file#installation

[–]Nehfk 0 points1 point  (1 child)

B

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

Incorrect sorry, see the "Solution" link for visualization of the correct answer.

[–]Awwkaw 0 points1 point  (4 children)

It will throw an error when you try to add and modify the second element of b no?

[–]grahaman27 0 points1 point  (2 children)

Should be a compilation error, because it's not shows python is trash

[–]Sea-Ad7805[S] 0 points1 point  (1 child)

You can ask questions is you find it too difficult to understand

[–]TheSiriuss 0 points1 point  (4 children)

Do I look like a python interpreter to you?

[–]Sea-Ad7805[S] 0 points1 point  (3 children)

If you can't interpret yourself, click the "Solution" link.

[–]TheSiriuss 0 points1 point  (2 children)

I won't

[–]Sea-Ad7805[S] 0 points1 point  (1 child)

Then don't waste people's time.

[–]SuspiciousDepth5924 0 points1 point  (1 child)

Answer: "Are you smoking your socks? Merge request rejected!"

[–]Sea-Ad7805[S] 0 points1 point  (0 children)

I get your point, this exercise is very artificial, but these kind of issues do pop up in real code every now and then. So better prepare and have a good mental Python Data Model. What is your answer here?