Iterators are objects that can be iterated upon. What a revelation, duh!
Whenever you write a For Loop, Python internally processes it via iterators.
Iterators have an iter() method which returns an iterable object, and a next() method which is used to get the next value in the iteration.
So, to implement your own iterators, it must have both and you must keep a track of indexes as well. It’s tedious.
Generators are a smarter and quicker way to implement iterators.
They look very similar to normal functions, but they have the “Yield” statement instead of the usual Return.
What’s the difference?
With Generators, you “Yield” outputs multiple times, and the yield statement need not be the last statement, unlike Return statement.
Unlike functions, Generators output the values one at a time, which is very handy when the sequence is large and you don’t want to kill your RAM.
To implement generators, you can also use the Generator Expressions!
You might argue that these look just like normal functions and list comprehensions, but they’re not.
Both return Generator objects on being called, and to get the values out, you either need to put in a loop or call the next() method each time.