{"cells":[{"cell_type":"markdown","metadata":{},"source":"Implementing Iteration\n======================\n\n"},{"cell_type":"markdown","metadata":{},"source":["## Agenda\n\n"]},{"cell_type":"markdown","metadata":{},"source":["1. Review: Iteration\n2. Details: *iterables*, *iterators*, `iter`, and `next`\n3. Implementing iterators with classes\n4. Implementing iterators with *generators* and `yield`\n\n"]},{"cell_type":"markdown","metadata":{},"source":["## 1. Review: Iteration\n\n"]},{"cell_type":"markdown","metadata":{},"source":["*Iteration* simply refers to the process of accessing — one by one —\nthe items stored in some container. The order of the items, and whether\nor not the iteration is comprehensive, depends on the container.\n\nIn Python, we typically perform iteration using the `for` loop.\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["# e.g., iterating over a list\nl = [2**x for x in range(10)]\nfor n in l:\n print(n)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["# e.g., iterating over the key-value pairs in a dictionary\nd = {x:2**x for x in range(10)}\nfor k,v in d.items():\n print(k, '=>', v)"]},{"cell_type":"markdown","metadata":{},"source":["## 1. Details: *iterables*, *iterators*, `iter`, and `next`\n\n"]},{"cell_type":"markdown","metadata":{},"source":["We can iterate over anything that is *iterable*. Intuitively, if\nsomething can be used as the source of items in a `for` loop, it is\niterable.\n\nBut how does a `for` loop really work? (Review time!)\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["l = [2**x for x in range(10)]"]},{"cell_type":"markdown","metadata":{},"source":["## 1. Implementing iterators with classes\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["class MyIterator:\n def __init__(self, max):\n self.max = max\n self.curr = 0\n\n # the following methods are required for iterator objects\n\n def __next__(self):\n pass\n\n def __iter__(self):\n pass"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["it = MyIterator(10)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["next(it)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["it = MyIterator(10)\nwhile True:\n try:\n print(next(it))\n except StopIteration:\n break"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["it = MyIterator(10)\nfor i in it:\n print(i)"]},{"cell_type":"markdown","metadata":{},"source":["For a container type, we need to implement an `__iter__` method that\nreturns an iterator.\n\n"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["class ArrayList:\n def __init__(self):\n self.data = []\n\n def append(self, val):\n self.data.append(None)\n self.data[len(self.data)-1] = val\n\n def __iter__(self):\n pass"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["l = ArrayList()\nfor x in range(10):\n l.append(2**x)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["it = iter(l)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["type(it)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["next(it)"]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["for x in l:\n print(x)"]},{"cell_type":"markdown","metadata":{},"source":["## 1. Implementing iterators with generators and `yield`\n\n"]},{"cell_type":"markdown","metadata":{},"source":["What's a \"generator\"?\n\n"]}],"metadata":{"org":null,"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.5.2"}},"nbformat":4,"nbformat_minor":0}