Title here
Summary here
Let’s look at the `List` type from the previous example again. In that example, we had an `AllElements` method that returned a slice of all elements in the list. With Python's iterators, we can do it better - as shown below.
```python
class List:
class Element:
def __init__(self, val, next=None):
self.val = val
self.next = next
def __init__(self):
self.head = None
self.tail = None
def push(self, value):
if self.tail is None:
self.head = self.tail = self.Element(value)
else:
self.tail.next = self.Element(value)
self.tail = self.tail.next
def all(self):
current = self.head
while current is not None:
yield current.val
current = current.next
def gen_fib():
a, b = 1, 1
while True:
yield a
a, b = b, a + b
def main():
lst = List()
lst.push(10)
lst.push(13)
lst.push(23)
for e in lst.all():
print(e)
all_elements = list(lst.all())
print("all:", all_elements)
for n in gen_fib():
if n >= 10:
break
print(n)
if __name__ == "__main__":
main()
All returns an iterator, which in Python is simply a generator. Here’s a function returning an iterator over Fibonacci numbers: it keeps running as long as we keep calling yield
.
Since List.all
returns an iterator, we can use it in a regular loop.
Once the loop hits break
or an early return, the generator will stop yielding further values.