I've made an iterable Squares object in 4 way. The classical class, generator style and just for fun a closure style and an improved(?) closure style.
class
class Squares:
def __init__(self, n):
self.n = n
def __iter__(self):
return self.SquaresIterator(self.n)
class SquaresIterator:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
result = self.i ** 2
self.i += 1
return result
It works as expected
sq_class = Squares(5)
list(sq_class)
[0, 1, 4, 9, 16]
# calling again will create a new iterator
list(sq_class)
[0, 1, 4, 9, 16]
generator
def squares(n):
for i in range(n):
yield i ** 2
sq_gen = squares(5)
list(sq_gen)
[0, 1, 4, 9, 16]
# calling again will return empty [] is OK, generator exhausted.
list(sq_gen)
[]
closure
def Squares(n):
def inner():
return squares_gen(n)
def squares_gen(n):
for i in range(n):
yield i ** 2
return inner
sq_closure = Squares(5)
list(sq_closure())
[0, 1, 4, 9, 16]
# calling again the inner will create a new generator so it is not exhausted
list(sq_closure())
[0, 1, 4, 9, 16]
improved(?) closure
def Squares(n):
def inner():
return squares_gen(n)
def squares_gen(n):
for i in range(n):
yield i ** 2
inner.__iter__ = lambda : squares_gen(n)
return inner
sq_closure = Squares(5)
list(sq_closure)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-beb02e61ccfb> in <module>
----> 1 for i in sq:
2 print(i)
TypeError: 'function' object is not iterable
What I wanted to try is attach the __iter__ function to the inner function object and return a generator and I can leave the ()-s and I can use the returned inner as an iterable object.
What is the exact definition of the iterable protocol? It seems, only the presence of the __iter__ function is not enough.
squares = map(lambda x: x*x, itertools.count())orsquares = (x*x for x in itertools.count()). Useisliceto take a finite prefix of the sequence:list(itertools.islice(squares, 5)) == [0,1,4,9,16]