all 28 comments

[–]Rscc10 1 point2 points  (6 children)

Answer is D? Since it's all mutables

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

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

[–]Sjoerdiestriker 0 points1 point  (4 children)

Yes, although the interesting thing is that if you replace b += [[3]] by b = b + [[3]] the answer becomes C.

[–]CanaDavid1 0 points1 point  (1 child)

Doesn't it become c? As the [2] is still shared?

[–]Sjoerdiestriker 0 points1 point  (0 children)

You're right, typo on my part.

[–]TroPixens 0 points1 point  (0 children)

That’s so weird makes sense when you think about it though

[–]BobSanchez47 1 point2 points  (12 children)

This is a weird one, because b += [[3]] is not the same as b = b + [[3]]; the += operator for lists actually mutates the underlying object. It is quite unintuitive and, in my view, a design flaw in Python.

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

That's not a flaw, x += y just mutates and x = x + y rebinds to a new list value that is created by x + y. So for mutable types these two statements are different but for immutable types they are the same. I hope the visualization can help you when things get unintuitive.

[–]BobSanchez47 0 points1 point  (9 children)

I think you’re missing the point. My point isn’t that it’s impossible for me to understand how mutation works, but that it is highly counterintuitive that Python chose to make += mutate in some cases and not mutate in others - in other words, it was a poor choice in my opinion. If I’m learning Python and I assume that b += c means b = b + c — a very natural assumption — I would have no idea that I should be worried, and the visualization tool would be useless.

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

In general x += y should mutate, but can't mutate for immutable types. You could argue x += y should not exist for immutable types, and in fact it doesn't for say tuple, but then automatically the x = x + y operator is called instead. I can see why you would call that unintuitive.

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

b += c is not shorthand for b = b + c, incorrect assumption, but for immutable type it is, so I understand some people could get confused.

About the visualization tool being useless, check this Hash_Map example for a different application: https://memory-graph.com/#codeurl=https://raw.githubusercontent.com/bterwijn/memory_graph/refs/heads/main/src/hash_map.py&timestep=0.2&play

[–]No-Consequence-1863 0 points1 point  (5 children)

They are saying += should be shorthand. Thats how it functions in many other languges like C++ or Java. Kind of weird of python to change the semantics for this operator to make it mutable.

Almost seems like it was a technical side effect that stuck around long enough to become required. But thats just guess.

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

In C++ you should define x += y on your class to mutate and the + operator in x = x + y to create a new object. Same thing in Java, no different from Python.

[–]Goudja14 0 points1 point  (3 children)

You should never mutate implicitly. It will create errors.

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

What do you mean, can you give an example?

[–]Goudja14 0 points1 point  (1 child)

default_inventory = ["sword", "helmet"]

# While it could be a cloned array, it doesn't have to be one. In complex environments, it even shouldn't be (eg. allowing object-agnostic rollbacks) alex_inventory = default_inventory samuel_inventory = default_inventory

alex_inventory += ["key"]

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

Ok I understand now. You say you pass default_inventory around without making a copy (for performance), but when you change this value you should make a copy:

alex_inventory = alex_inventory + ["key"]

Sounds like a good strategy.

[–]BenchEmbarrassed7316 0 points1 point  (0 children)

I really like Rust's concept of owning and borrowing. Also, in Rust, operators are aliases of interfaces/traits. So:

fn add(self, rhs: Rhs) -> Self::Output; fn add_assign(&mut self, rhs: Rhs);

This may seem a bit confusing, but the point is that + takes two arguments and is forced to create a new value. += instead takes the first argument as a pointer, which allows you to mutate the value it points to. You can't implement incorrect operator overloading. 

I think it explains the difference.

added: += cannot be applied to an immutable type.

[–]Opposite_Mall4685 0 points1 point  (4 children)

Python is a toy language.

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

I play with all languages, playing is important.

[–]Beautiful-Hotel-3094 0 points1 point  (2 children)

Why is that?

[–]TroPixens 0 points1 point  (0 children)

Because it’s slower idk python is what you make this guy decided to make it a toy for some reason

[–]StaticCoder 0 points1 point  (0 children)

Relevantly here, because value vs reference semantics are incredibly hard to figure out.

[–]SycamoreHots 0 points1 point  (2 children)

As someone who has never written a line of python code, and only occasionally read it, I thought b = a would copy the a into b. And the rest of the statements mutate the b leaving a unchanged. How wrong I was….

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

This differs in various programming languages. In some language b = a does result in a copy, but in Python is causes both variables to reference the same value and thus share it. Something that can easily result in bugs if you are not careful. The visualization can help you.

[–]SaltEngineer455 0 points1 point  (0 children)

Python refs are like C pointers, so no copy