Am new to Python and am trying to implement my own Cycle method mocking itertools.cycle method. I have written the following code. It gives the output, but with an exception.
def cycle(iterinp):
iter1 = iterinp
iterVal = iter(iter1)
while True:
try:
yield next(iterVal)
except TypeError:
print("Argument is not an iterator")
except:
iter1 = iterinp
iterVal = iter(iter1)
c = cycle([1,2,3])
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))
print(next(c))
Output :
1
2
3
1
2
3
Exception : Exception ignored in: <generator object cycle at 0x0000016BECE19C40> RuntimeError: generator ignored GeneratorExit
When a program exits, it tries to perform cleanup by calling the __del__
method of any remaining objects. For generator objects the __del__
method would call their close
method, which raises the GeneratorExit
exception so that the generators would exit normally.
But since your code blindly catches all exceptions with the except:
block, the GeneratorExit
exception has no way to propagate, causing the said RuntimeError
complaining about GeneratorExit
getting ignored.
The solution is to simply be specific about the type of exception you actually want to catch while letting other exceptions propagate. In this case you really only want to catch StopIteration
, so change:
except:
to:
except StopIteration:
Demo: https://replit.com/@blhsing/StainedFumblingOrganization
Note that the __del__
method is not guaranteed to be always called even upon program exit, which is why @SuperStormer commented about not being able to reproduce the error in his/her attempt.
Furthermore, itertools.cycle
is supposed to take any iterable object as an argument, not just a list, but with your implementation, once the input iterable is exhausted, it cannot be restored with a simple call of iter
unless it is a sequence such as a list as it happens to be the case with your example.
itertools.cycle
's documentation already has a perfectly fine example of a good Python implementation for your reference:
Make an iterator returning elements from the iterable and saving a copy of each. When the iterable is exhausted, return elements from the saved copy. Repeats indefinitely. Roughly equivalent to:
def cycle(iterable): # cycle('ABCD') --> A B C D A B C D A B C D ... saved = [] for element in iterable: yield element saved.append(element) while saved: for element in saved: yield element