The issue here is not in fact a problem with how iterators work in python as opposed to how assignment works on most python types. When the asker attempts to overwrite the value of lett which is indeed an alias to ab[index] and should seem logically to work, this is not in fact what is happening, instead lett (the reference or pointer lett, not the value it points to) is being reassigned to point to a constant of it's new value, this is quite different from overwriting the bytes at the memory location it points to. This way of working is necessary to allow python's duck typing to work where a variable name can over time point to different types with different sizes. Please see this page for more explanation of what is happening here: http://gestaltrevision.be/wiki/python/aliases
The closest we could achieve is a hand made 'mutable integer' type which will allow it's underlying value to change unlike python ints. However there is little point in going over this by hand here as it has already been explained in this question. Though the question is quite different it is the same underlying issue and the solution is equally acceptable. However if you are doing this I would consider first if you can restructure your code to avoid this in the first place as it is quite a dangerous and accident prone way of working.
Here's an example from an answer to the "increment int object" question for a full explanation of how to hack this together please see the question linked above, note that this example only includes decrementing, the other operators would have to be implemented in the same way:
import sys
class FakeInt(int):
def __init__(self, *arg, **kwarg):
self._decr = False
int.__init__(self, *arg, **kwarg)
def __neg__(self):
if self._decr:
upLocals = sys._getframe(1).f_locals
keys, values = zip(*upLocals.items())
i = list(values).index(self)
result = FakeInt(self-1)
upLocals[keys[i]]=result
return result
self._decr = not self._decr
return self