Finishing "fizzbuzz" and announcing the Python Growth Challenge

March 16, 2021

In my last post, I talked about how using coding challenges, or katas, can help you grow as a python developer.

In particular, I mentioned how the Fizz Buzz challenge enabled me to think about the “O” in the SOLID Principles. In this article, I will explain how I came to my solution.

Planning ahead of time

To quickly recap my intention, I wanted to create a solution that would print “fizz” for every number divisible by three. I would then expand its capabilities to include “buzz” and “fizzbuzz” without changing the original code.

I quickly realized that I needed to split the responsibilities between multiple components. I needed:

  • something to generate numbers
  • something to process numbers with the intention of solving the “fizz” part of the problem
  • something to coordinate the logic of processing the numbers

I decided to take the first and third needs together and created a function that would take two arguments, the number to count to, and a list of functions to process each number.

def count_and_process(count_to: int, funcs: List[Callable]):
    pass

Generating the numbers is easy in python. I created a range object that would generate each number needed, and I set that number to a variable in a for loop:

def count_and_process(count_to: int, funcs: List[Callable]):
    for i in range(1, count_to + 1):
    ...

Next, I had to solve a tricky part. Since I am receiving a list of functions to call to process each number, I felt like I needed a way to pass it two pieces of state: the current number, and the result from every other function that proceeded it. I decided to do that with tuples. The first element of the tuple would be the current number. The second element is the processed result.

In my mind, I could see a stream of data that would look like this:

# starting -> processed by "fizz" -> processed by "buzz"
  (1, 1)      (1, 1)                 (1, 1)
  (2, 2)      (2, 2)                 (2, 2)
  (3, 3)      (3, 'fizz')            (3, 'fizz')
  (4, 4)      (4, 4)                 (4, 4)
  (5, 5)      (5, 5)                 (5, 'buzz')
  (6, 6)      (6, 'fizz')            (6, 'fizz')
  (7, 7)      (7, 7)                 (7, 7)
  (8, 8)      (8, 8)                 (8, 8)
  (9, 9)      (9, 'fizz')            (9, 'fizz')
...

This way, each processing function would see what the current number is, but would also have the opportunity to interact with the results from previous processing functions.

I needed to write code that would create the tuple, hand it off to the processing functions, and return the result.

def count_and_process(count_to: int, funcs: List[Callable]):
    for i in range(1, count_to + 1):
       data = (i, i)
       for f in funcs:  
           data = f(data)  
    yield data[1]

All that is left is to create the function that would handle the processing of the numbers. My choice of using tuples to pass the data around means I need to create a new tuple whenever we need to print out something other than the number.

def fizz_3(data: Tuple[int, Union[int, str]]):  
    if data[0] % 3 == 0:  
        data = (data[0], 'fizz')  
    return data

To make the exercise work as intended, printing the numbers from 1–100, one would do this:

>>> print(list(count_and_process(100, [fizz_3])))
[1, 2, 'fizz', 4, 5, 'fizz', 7, 8, 'fizz', 10 ...]

Writing a buzz function

This is where the rubber met the road. My previous function 'fizz’ed at every third number. Now I needed to add the “buzz”.

Thankfully, my plan worked. The hard work had already been done. I first needed to create the function that would produce the “buzz” results:

def buzz_5(data: Tuple[int, Union[int, str]]):  
    if data[0] % 5 == 0:  
        if isinstance(data[1], str):
            data = (data[0], data[1] + 'buzz')
        else:
            data = (data[0], 'buzz')
    return data

Then, all I had to do was hooked it into the process:

>>> print(list(count_and_process(10, [fizz_3, buzz_5])))
[1, 2, 'fizz', 4, 'buzz', 'fizz', 7, 8, 'fizz', 'buzz']

It’s your turn

Was my solution the best ever? No. But it really helped me to think through how to structure my code.

How did you solve it? What challenges did you set for yourself? Would you want to do more of this?

I am creating a Python Growth Challenge for the month of April. The idea is to gather a group of us to practice katas like this. Each week, each of us will challenge ourselves to do something we’re not great at. I’ll provide the code kata, and we’ll meet together to discuss what we’ve each learned. We’ll do it for five weeks and see how we’ve grown.

If you’re interested, please fill out my interest form. To make sure we all can talk, I need to keep this group small, so I will need to cap it at 20 people.

But please join us, no matter your skill level!

Read other articles

Supercharge your projects!

Expand your capabilities, and increase your confidence by building on four foundational items.

Get the guide
Cover image and one internal page

© 2021 Everyday Superpowers

LINKS
About | Articles | Resources

CONTACT
chris@may.org

Free! Four simple steps to solid python projects.

Reduce bugs, expand capabilities, and increase your confidence by building on these four foundational items.

Get the Guide

Join the Everyday Superpowers community!

We're building a community to help all of us grow and meet other Pythonistas. Join us!

Join

Subscribe for email updates.