FizzBuzz: a Python deep-dive
Imagine you’re being interviewed for a job in Python. It’s the moment you’ve been waiting for — your interviewer has just asked you to write a FizzBuzz programme! This is a deep-dive into the FizzBuzz interview question, based on a real life experience of mine.
For the uninitiated, FizzBuzz is a counting game in which numbers divisible by 3 are replaced by “Fizz” and numbers divisible by 5 are replaced by “Buzz”. Numbers divisible by both 3 and 5 are replaced by FizzBuzz, hence the name of the game.
A quick solution
So how do you go about it? Well, let’s break it down into its components. We need ways of:
- Counting, which Python conveniently offers via range
- Checking if a number is divisible by 3 or 5 (or both), which can be done with the modulo (%) operator
- Displaying the output, which can be done via print
So what does a quick solution look like? Well, here’s one!
This solution gets the job done, and it is good enough to show you know some basic Python! FizzBuzz, after all, is only supposed to be a way to screen for basic programming skills. But, to me at least, this solution doesn’t look very neat. If we consider a number like 7, there are some checks that get done twice — we do two checks to see if 7 is divisible by 3, for example.
So, how do we improve on our above solution? Well, the trick is to notice that Fizz takes precedence over Buzz — i.e., if a number is divisible by both 3 and 5, we say FizzBuzz and not BuzzFizz. This means, for each number, you can start with an empty string and build it up as you do checks in order of precedence, like so:
But wait, there’s more…
Great, that looks quite neat! Looking at this, your interviewer says: “Now, change it to play FizzBuzzBang, where you include Bang if a number is divisible by 7”.
In the original structure, this would have been horrible to do. In our latest version, however, we just add a new if-statement.
Since our interviewer is toying with alternatives divisors and strings, packaging up the code in a function where we can change the arguments based on their specification makes sense. In the above example, all that actually changes between the if-statements is the divisor and its associated string. So, with that in mind, we can take all of that parameterisation out of the function and do something like the following:
But you’re not done yet…
Just when you think you’re done, the interviewer says: “Straight forward division is boring — print Bang when the number is two less than a number that is divisible by seven, instead”. Ugh. The checks are no longer the same, so how do we approach this new specification?
The trick here is to realise that you can pass functions as arguments to functions. So, rather than passing a divisor, we can refactor our code to take a function that takes number as a parameter and returns a boolean (i.e., True or False) indicating whether or not we want to include the associated string. So, what does this look like?
At this point, the interviewer moved on to a different topic (a story for another day), but I would argue that the previous solution is a bit unwieldy — do we really need to define full functions for those checks? Personally, I feel a lambda function makes understanding the code a little easier.