CodingNic

Generators, Iterators, and Decorators

Generators, Iterators, and Decorators Exercises

Generators, Iterators, and Decorators 35 min read

Generators, Iterators, and Decorators Exercises

Objectives

This chapter introduces no new concepts: it’s a chance to put generators, iterators, and decorators into practice.

Part I: Generators

get_next_multiple

Accepts a number and returns a generator that yields successive multiples of it, forever.

python
gen_multiple_of_two = get_next_multiple(2)
next(gen_multiple_of_two)  # 2
next(gen_multiple_of_two)  # 4
next(gen_multiple_of_two)  # 6
next(gen_multiple_of_two)  # 8

gen_multiple_of_thirteen = get_next_multiple(13)
next(gen_multiple_of_thirteen)  # 13
next(gen_multiple_of_thirteen)  # 26
next(gen_multiple_of_thirteen)  # 39
next(gen_multiple_of_thirteen)  # 52

is_prime

Accepts a number and returns True or False depending on whether it’s prime.

python
is_prime(11)   # True
is_prime(122)  # False

get_next_prime

Returns a generator that yields the next prime number each time, capping out at 1000.

python
gen = get_next_prime()
next(gen)  # 2
next(gen)  # 3
next(gen)  # 5

Part II: Decorators

double_result

A decorator that doubles the return value of the function it wraps.

python
def add(a, b):
    return a + b

add(5, 5)  # 10

@double_result
def add(a, b):
    return a + b

add(5, 5)  # 20

only_even_parameters

A decorator that only calls the wrapped function if every argument is even. Otherwise it returns "Please only use even numbers!".

python
@only_even_parameters
def add(a, b):
    return a + b

add(5, 5)  # "Please only use even numbers!"
add(4, 4)  # 8

@only_even_parameters
def multiply(a, b, c, d, e):
    return a * b * c * d * e

Callback: once → @run_once

Back in the functions module, you wrote a once function that took another function and returned a version of it that could only run one time. Now that you know how decorators work, come back and rewrite it as a proper decorator, run_once:

python
@run_once
def add(a, b):
    return a + b

add(2, 2)   # 4
add(2, 20)  # None

Part III: More Practice

sum_index

Accepts a list or tuple and returns the sum of all its values. Bonus: make it accept a variable number of individual arguments too, not just a single list.

python
sum_index([1, 2, 3, 4])  # 10

zip

Research the built-in zip() function: what does it do, and when would you reach for it? Try it out:

python
names = ["Erin", "Jordan", "Maya"]
scores = [90, 85, 78]

list(zip(names, scores))
# [('Erin', 90), ('Jordan', 85), ('Maya', 78)]

Try It

  1. Implement get_next_multiple and is_prime, then use is_prime to help build get_next_prime.
  2. Implement double_result and only_even_parameters, and test both against the examples above.
  3. Rewrite once as @run_once, confirming it still only lets the wrapped function run a single time.

Recap

You can now write generator functions with yield, understand the relationship between generators and iterators, and write your own decorators, including revisiting earlier code to decorate it properly. That’s the toolkit Module 8 set out to build.

Next module: web scraping, pulling data from live web pages.