range vs np.arange vs xrange
range creates a list, so if you do range(1, 10000000) it creates a list in memory with 10000000 elements.np.arange pretty much like a range function, but it returns an numpy array instead of a list.xrange is a sequence object is a that evaluates lazily. (much less memory is used).
Efficiency
1 | %timeit for i in range(1000000): pass |
The Iteration Protocol
The built-in function iter takes an iterable object and returns an iterator.
1 | x = iter([1, 2, 3]) |
Each time the next method is called on the iterator, it gives the next element. If there are no more elements, it raises a StopIteration.
Generators
Generators simplifies creation of iterators. A generator is a function that produces a sequence of results instead of a single value.
1 | def yrange(n): |
Each time the yield statement is executed the function generates a new value.
1 | y = yrange(3) |
So a generator is also an iterator. One does not have to worry about the iterator protocol.
When a generator function is called, it returns a generator object without even beginning execution of the function. When next method is called for the first time, the function starts executing until it reaches yield statement. The yielded value is returned by the next call.
Example:
1 | def foo(): |
Generator Expressions
Generator Expressions are generator version of list comprehensions. They look like list comprehensions, but returns a generator back instead of a list.
1 | a = (x*x for x in range(10)) |
Relationship between Generator, Iterator and Iterable
