Iteration in Python Flashcards
What makes an object iterable? Give the simple AND Pythonic explanation, and give 3 examples.
Simple: Can be looped (iterated) over
Pythonic: Returns an iterator when passed to iter()
, i.e. the object has dunder methods \_\_iter\_\_()
and/or \_\_getitem\_\_()
defined.
Examples: str, list, dict
What is an iterator? Give the simple AND Pythonic explanation.
Simple: An iterable object that has two main actions:
* Returns data one item at a time
* Keeps track of current and visited items
Pythonic: An iterable object that implements the iterator protocol, i.e. defines \_\_next\_\_()
and returns itself within \_\_iter\_\_()
What is the purpose of \_\_next\_\_()
?
It’s used by an iterator to:
* Define exactly how it will traverse through its stored values
* Return the next value in the iteration
* Keep track of which values have already been called
* Raise a StopIteration
exception when no more values are available
What’s one memory-related benefit of using iterators?
Iterators allow you to process the entire dataset one item at a time, which removes the need to store the entire dataset into memory.
What are the functions of the 3 types of iterators?
- Take stream of data, yield original data (classic iterator)
- Take stream of data, transform original data and yield new data
- Take no input data, yield results from a computation
What does it mean when you get a StopIteration
error when calling an iterator with next()
?
The iterator object is consumed, i.e. it has iterated through all of its values and you’ll need to create another one if you want to perform another iteration.
Implement a classic iterator that takes a sequence of values as an input and yields each value sequentially
create an iterator that takes a sequence of values at instantiation and is
class SequenceIterator: # store the sequence and set the index to 0 at initialization def \_\_init\_\_(self, sequence): self._sequence = sequence self._index = 0 # per iterator protocol, iterators will always return itself in \_\_iter\_\_() def \_\_iter\_\_(self): return self # return the current value of the sequence and increment the index by 1 # if index is incremented past the sequence, raise StopIteration def \_\_next\_\_(self): if self._index < len(self._sequence): item = self._sequence[self._index] self._index += 1 return item raise StopIteration
What does iter()
do?
Calls an iterable object’s \_\_iter\_\_()
method to return an iterator. If \_\_iter\_\_()
doesn’t exist but \_\_getitem\_\_()
does, it will return an iterator that calls \_\_getitem\_\_()
with i = range(inf)
until a StopIteration
exception is raised
T/F: An object isn’t iterable without \_\_iter\_\_()
defined
False, as long as \_\_getitem\_\_()
exists instead. If both don’t exist, then it’s True.
Implement Python’s for
loop using the iterator protocol
iterator = sequence.\_\_iter\_\_() while True: try: # get the next item using \_\_next\_\_() item = iterator.\_\_next\_\_() except StopIteration: break else: # the loop's code goes here print(item)
What does it mean when an iterator is lazy?
It means that an iterator will only calculate and/or return one value at a time. It is hugely efficient in terms of memory consumption because your code will only require memory for a single item at a time.
How do you create an infinite iterator?
Create a normal iterator, but don’t include the StopIteration
exception
Which of Python’s abstract base classes (ABCs) can you inherit to more easily create custom iterators?
collections.abc.Iterator
, which
What is a generator function?
A unique function that returns a generator iterator and keeps track of its state with the yield
keyword
How do generator functions/expressions differ from custom iterable classes?