1

Learning programming in Python and I am doing some challenges. I've run into something I haven't learned yet and was curious what this code is doing.

So my challenge is called the "FizzBuzz" challenge. The instructions are simple:

Create a function that takes a number as an argument and returns "Fizz", "Buzz" or "FizzBuzz".

If the number is a multiple of 3 the output should be "Fizz". If the number given is a multiple of 5, the output should be "Buzz". If the number given is a multiple of both 3 and 5, the output should be "FizzBuzz". If the number is not a multiple of either 3 or 5, the number should be output on its own.

I wrote this code to solve it (obviously it can be better):

def fizz_buzz(num):
    if num % 3 == 0 and num % 5 == 0:
        return 'FizzBuzz'
    elif num % 3 == 0:
        return 'Fizz'
    elif num % 5 == 0:
        return 'Buzz'
    else:
        return str(num)

But, once I submitted my solution I was able to see the top solution, which is:

def fizz_buzz(num):
    return "Fizz"*(num%3==0) + "Buzz"*(num%5==0) or str(num)

My question is what is the * doing here? Can someone point me to documentation or resources that addresses what this persons code has done? I don't find it super readable but it is apparently the best solution to the problem.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
sdiggles
  • 43
  • 4
  • 2
    Looks to be multiplying "Fizz" or "Buzz" times 1 or 0 (true or false) to determine whether to output it or not. – Brian Mar 06 '20 at 18:52
  • `or` with two strings returns the first if it's not empty, or the second if it is empty – Ed Ward Mar 06 '20 at 18:55
  • Asking for off-site resources is off-topic on Stack Overflow, but this is a good question otherwise, so I've removed that part from the title. I also made the title more specific while I was there. – wjandrea Mar 06 '20 at 19:16

5 Answers5

4

bool in Python is a subclass of int; True has the value 1, False, 0.

Sequences (including str) in Python can be multiplied, to get the sequence repeated that many times, so:

"Fizz"*(num%3==0)

multiplies "Fizz" by 1 (numeric value of True) when num % 3 == 0, producing the original string, and by 0 (numeric value of False) otherwise, producing the empty string.

The same work is done with "Buzz" and concatenated. If both of them produced the empty string (which is falsy), then the or means str(num) is evaluated and returned (Python's or and and don't evaluate to strict True or False, they evaluate to the last item evaluated, and short-circuit, so or always evaluates to the first truthy item, or the last item in the or chain regardless of truthiness).

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Alright, so broken down: ``` "Fizz"*(num%3==0) ``` This isn't num%==3 * fizz, right? It's more like the format of a comprehension and I'm assuming the *(whatever) is the way you do this? Or, is it literally multiplying? ``` + "Buzz"*(num%5==0) ``` Same thing as Fizz but I understand the + between them. ``` or str(num) ``` Now, if I understand you then if this function was passed and not a multiple of 3 or 5 then the **or str(num)** will be true? – sdiggles Mar 09 '20 at 16:38
  • 1
    @sdiggles: There is literal multiplication going on (with sequences, including `str`, it performs repetition; repeating zero times means "get empty version of sequence"), either `"Fizz" * True` or `"Fizz" * False`, where `True == 1` and `False == 0`. `+` on sequences means concatenation. `or str(num)` need not be true or false (although it always will be true since it numbers converted to `str` produce non-empty `str`, which are always true). If the part before the `or` is falsy, then the part after is the result of the expression. – ShadowRanger Mar 09 '20 at 17:41
2

Firstly, shorter doesn't always mean better. In this case, your solution is fine, and the "top solution" is clever, but needlessly confusing, as you're aware :P

The star is doing string multiplication, and it's exploiting the fact that False == 0 and True == 1. So if num is divisible by 3, you get 'Fizz' once, and if num is divisible by 5, you get 'Buzz' once. Otherwise you get an empty string, '', and because an empty string is falsy, the or clause means it will be replaced by str(num).

wjandrea
  • 28,235
  • 9
  • 60
  • 81
0

The * is string multiplication as usual. It's just multiplying by 0 or 1 based on whether the condition to print the phrase is met. If neither condition is met, it defaults to returning the number, as it should.

Mark Snyder
  • 1,635
  • 3
  • 12
0

I don't know about a resource, but I can tell you what it does. The phrase num%3==0 is a Boolean which is true if the number is divisible by 3. If that's the case, this phrase returns a 1 (or 0 if False). Same for num%5==0 and divisible by 5. This is then being multiplied by the string Fizz and/or Buzz and concatenated together, where multiplying by 1 returns the string and 0 nothing. If neither of those holds, it returns str(num).

Todd Burus
  • 963
  • 1
  • 6
  • 20
0

I do not know the link to any documentation or resource about it, but I can explain it to you.

Firstly in python str can be multiplied by a number, for instance 'Fizz' * 3 will return 'FizzFizzFizz' or 'Fizz' * 0 will return '', an empty string.

Secondly bool in python can be also recognized as int, i.e. True is 1 and False is 0.

Thirdly in python strings can be added e.g. 'Fizz'+'Buzz' will return 'FizzBuzz'

What the best solution guy does is very simple by num%3==0 he gets bool and just multiplies the str 'Fizz' or 'Buzz' by it and returns.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
r3dfear
  • 3
  • 4