Assignment happens at places, where you don't expect it.
For example a for-loop is an assignment.
For each iteration the returned result from the iterator is assigned to the name.
When you create a class or a function, it's an assignment of the code block to a name.
The name is just a reference to the in memory living object.
An object can have many references (assigned to names).
The term
variables
is miss-leading.
a = 42
This code means, that a is now a reference to 42, which is the type int, which is in memory.
b = a
Now it's getting complicated. The name
a
is pointing to
42
.
The name
b
is not pointing to a.
Instead it has the reference to object
42
If you change now the name a, b will still hold the reference to
42
.
In other words, the assignment is by reference and not by value.
This is in Python a big pitfall.
There is another case, where you work with mutable types.
This means a value or many values can be changed on the object itself.
int, float, tuple, str, frozenset are immutable types, which could not change the value after creation.
The counter part are list, dict, set (and all other I forgot to name). They are mutable.
This means you can change the content of a list, dict, set etc. and all names, which have a reference to
the object which has still access to the mutated object.
It's very late, I do not have enough time to explain arithmetic operators with the right terms.