How to change iterator elements using iterators? That is, how to get write-iterators in Python?

I really like the Python syntax, but since I'm starting from C ++, I don't understand anything about Python iterators. In C ++, there are 2 types of iterators - constant and modification (not constant). In python, it seems (for what I saw) that there is only the first view, and if you want to change the elements you need to use indexing, which does not seem convenient and so general to me. Let me illustrate a simple example:

ab = ["a", "b"] for (index, lett) in enumerate(ab): print "Firstly, lett is ab[index]?", lett is ab[index] lett = str(index) print lett print ab[index] print "But after, lett is ab[index]?", lett is ab[index] 

So I could not modify the list using an iterator. It just makes Lazy copies (see Wikipedia ), as I found with the is operator, so there is a way to say that I want it instead of directly modifying the iterator using neat

 for variable in iterable_object: 

syntax?

+4
source share
4 answers
 def iset(iterable): for i, x in enumerate(iterable): def setter(value): iterable[i] = value yield setter, x a = range(10) for set_x, x in iset(a): set_x(x * 2) print a 

prints

 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 
+3
source

Syntax

 for x in iterable 

doesn't create any lazy copies - it assigns the exact objects in the list x one by one. If these objects are mutable, you can change them:

 a = [[1, 2], [3, 4]] for x in a: x.append(5) print a 

prints

 [[1, 2, 5], [3, 4, 5]] 

Your example uses a list of strings. Strings are immutable in Python, so you cannot change them.

+9
source

The problem is not really a problem in how iterators work in python, and not how assignment works in most python types. When the crawler tries to rewrite the lett value, which is really an alias ab [index] and should seem to work logically, this is not really what is happening, but lett (the reference or lett pointer, not the value that it indicates to) is reassigned. to indicate the constant of the new value, this is very different from overwriting bytes at the memory location it points to. This way of working is necessary to allow duck pythons to be printed, where the variable name may eventually point to different types with different sizes. See this page for more details: http://gestaltrevision.be/wiki/python/aliases

The closest we could achieve is a manual type "mutable integer", which will allow us to change its base value, unlike python ints. However, there is little point in moving here, as this has already been explained in this matter . Although the question is completely different, it is one and the same main problem, and the solution is equally acceptable. However, if you do this, I would first think if you can rebuild your code to avoid this, in the first place, since this is a rather dangerous and accident-prone way of working.

Here is an example from the answer to the question "increment of int object" for a full explanation of how to hack this together, see the question related above, note that this example includes only decrement, other operators should 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 
0
source

A similar scenario ...

 >>> a = b = 0 >>> a = 42 >>> a, b (42, 0) >>> a = b = [0] >>> a[0] = 42 >>> a, b ([42], [42]) 

While python uses links inside, and tags a and b point to the same object 0 , saying a = 42 replaces a , not links to a . The list can be used as a workaround, but it is by no means elegant.

An iterator just like it is a real thing, but there is no way to β€œdereference”, and I can imagine that adding this function can break a whole bunch of other things.

I think the enumerate method is still correct.

0
source

All Articles