I'm programming an iterator object that returns modifications of itself and I want the original object to be part of the iteration process, so it needs to be returned before being modified.
...but:
yield inside __next__ will not work because it returns a different type (generator) in each iteration instead.yield inside __iter__ to get an iterator but then I couldn't use __next__ to get on-demand iterations (my object is a Turing machine, so a controlled step-by-step print of the tape would be nice).An example of working, but inefficient, code:
from copy import deepcopy
class MyObject():
def __init__(self, n):
self.n = n
def __str__(self):
return str(self.n)
def __iter__(self):
return self
def __next__(self):
if self.n >= 10:
raise StopIteration
self_copy = deepcopy(self)
self.n += 1
return self_copy
for x in MyObject(n=7):
print(x)
Output:
7
8
9
I'm probably missing something here but I can't figure it out.
Generator seems like a good idea. Replace your __iter__ and __next__ with this:
def __iter__(self):
while not self.n >= 10:
yield self
self.n += 1
(In this particular case we could of course do while self.n < 10: instead.)
Alternatively, to make your object itself its own iterator, as discussed in our comments below, you could use a flag:
class MyObject():
def __init__(self, n):
self.n = n
self.iterated_original = False
def __str__(self):
return str(self.n)
def __iter__(self):
return self
def __next__(self):
if not self.iterated_original:
self.iterated_original = True
else:
self.n += 1
if self.n >= 10:
raise StopIteration
return self
for x in MyObject(n=7):
print(x)
Or since iterated_original ideally is set to True after the original has been iterated, here's as late as I can do it:
def __next__(self):
if self.iterated_original:
self.n += 1
if self.n >= 10:
raise StopIteration
try:
return self
finally:
self.iterated_original = True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With