

Thanks a lot, I hope it can bring much value for you.


Thanks a lot, I hope it can bring much value for you.


The point of the visualization at the Solution link is precisely to help people get the right model of how labels and the data model in general works in Python. See the Explanation link for more details.


If you are interested see the dictionary docs (https://docs.python.org/3/builtins/stdtypes.html#dict):
d |= otherUpdate the dictionarydwith keys and values fromother, which may be either a mapping or an iterable of key/value pairs. The values ofothertake priority whendandothershare keys. Added in version 3.9.
Pick your answer and check the Solution link.


There is one important difference between a |= b and a = a | b, that is one part that makes this exercise difficult. See the dictionary docs (https://docs.python.org/3/builtins/stdtypes.html#dict):
d |= otherUpdate the dictionarydwith keys and values fromother, which may be either a mapping or an iterable of key/value pairs. The values ofothertake priority whendandothershare keys. Added in version 3.9.
Pick your answer and check the Solution link.
The zen of Python lies unless you’re Dutch. I’m Dutch and when I look out of my office I see the CWI where Guido wrote the original Python versions back in the day, see “Python the documentory” on YouTube.


I think the confusion comes from a += b being equivalent to a = a + b for immutable types, so some people generalize that incorrectly to mutable types too. Otherwise I think it’s pretty clear a += b mutates a, and a = a + b first computes a + b and then reassigns that to a so that its identity changes, just like in c = a + b.
If you implement these operations in a class you have to implement each dunder, __iadd__(self, other) and __add__(self, other) separately, same thing in C++.


Thanks, maybe I should have added that possible answer instead of ‘D’, adding one more feels too many.


If you don’t want mutability you have to go to a pure functional language like Haskell, but then you have to copy a big list every time you make a change. There are ways to optimize copying by secretly sharing data behind the scene but you pay a performance price in some way. Then again, Python is slow and has mutability but popular for other reasons.


Thanks, I’m pretty happy with it myself.


The difference between a |= b and a = a | b is exactly the same as the difference between a += b and a = a + b. Nothing new about that, try:
a = [1]
b = a
b += [2]
b.append(3)
b = b + [4]
b.append(5)
print(a)
or see: https://fosstodon.org/@bterwijn/116328991093782469
For immutable types there is no difference between a += b and a = a + b, try with a tuple.


This is what the solution link is supposed to give you at the end of the execution animation:
It’s hard to support all mobile browsers, on some it does work.


It’s mainly targeted to Python programmers at: https://programming.dev/c/python
The Solution link gives you a visualization of program execution, I’ve started to make the same sort of visualizer for C. What do you think?


Yes indeed, the ‘int’ objects are stored and searched in the set based on their value, and the ‘Value’ objects are stored/searched based on their identity unless you define the above __eq__ and __hash__ methods which cause them to be stored/searched based on value too. This is a Python design decision and that’s the point of this exercise. The fact that ‘int’ is an immutable type and we are replacing isn’t relevant. Try replacing/reassigning the ‘Value’ objects after added __eq__ and __hash__, and you get the same result as for ‘int’. So the thing that really matters is how __eq__ and __hash__ are defined, and the default for a user-defined class is as stated in the “Explanation:” above.
Maybe I should also show a class with __eq__ and __hash__ defined based on value, but then it gets a bit long. I’ll have to rethink this exercises so that the point comes across better as it now seems to confuse a lot of people based on the down-votes. Thanks for feedback anyway.


Sure, but a lot of people incorrectly think the __eq__ and __hash__ are defined based on value not identity, as they are for many other types say float, str, or tuple. But for a class the default __eq__ method is x is y instead of x == y and also __hash__ is based on identity.
Others assume that if you don’t define __hash__ for a class, that it doesn’t exists (like for list, set, or dict) so that a “TypeError: unhashable type: ‘Value’” exception is raised.
I thought it was an interesting exercise to share, but maybe too simple for this audience, or people are just not aware of the basic steps that happen when adding and searching values in a set/dict. Try the same with type int:
v1 = 1001
v2 = 1002
myset = {v1}
print(v1 in myset, end=' ')
v2 = 1001
print(v2 in myset, end=' ')
v1 = 1002
print(v1 in myset, end=' ')
and you see a different output. To do the same with the Value class add methods:
def __eq__(self, other):
return self.value == other.value
def __hash__(self):
return hash(self.value)


Another common naming convention in C++ is using an underscore as prefix for member variables: int _memberVariable{123};


Copying a list with a million elements every time you make a small change is not fun. Sure, you can optimize a bit behind the scenes, but that still gives a lot of overhead.


It’s definitely not the same. Similarly for a class you can define the __add__ dunder method for a + b and separately the __iadd__ dunder method for a += b. The first creates a new object, the latter changes/mutates the existing object a. For immutable types it is the same though.


Yes I understand your point, but I’m trying to reach out so people are aware and can use it in Python education. I feel it can really help beginners understand tricky concepts with ease, bit it’s hard to reach a bigger audience these days. Sorry for the repetition, I’ll guess I should cut back a bit.


Different languages make different choices. The disadvantage of Haskell is that if you want to change one value in a collection of a million values that it either makes a full copy or tries to optimize by sharing values behind the scene, both resulting in significant overhead. Most people already understand that pure functional programming languages don’t deliver except in very specific circumstances: Haskell TIOBE rating 0.32%, https://www.tiobe.com/tiobe-index/


Incorrect sorry, check the “Solution” link for the correct answer.
Thanks, but I also give a solution link, so people can already cheat if they really want too.