I have some observations that are mostly language-independent.
Document your functions
A clear description of functionality helps when you're considering re-using code in a new project. Get in the habit of writing good doc-comments early, so you're not caught out trying to unravel your logic when it matters!
Accept command-line arguments
It's tedious to test a program if you always need to supply inputs. Simple numbers are best provided as arguments when invoking the program (consider reading from the input stream as a fallback).
Validate inputs
Does it make sense to accept negative numbers? I don't think so; we should refuse to operate if any of the inputs are zero or less.
Separate computation and I/O
It's hard to unit-test code that produces output using print(). It's easier if we return an collection of values or if we write to a supplied iterator. Python helps us, because it allows us to write a generator simply by using yield to return each value.
Division is the most expensive of the basic arithmetic operations
getString() (which should be get_string() by PEP-8, but really needs to be something more informative) has no knowledge that it is being called with sequential values of num. That prevents a key optimisation that's possible if we inline the function. Then we're able to maintain variables to record the remainders without needing the % operator.
Modified code
Incorporating my suggestions, and some improvements from other answers:
#!/usr/bin/python3 import sys def fizzbuzz(max_num, fizz, buzz): ''' A generator that transforms the range [1..max_num], returning each number converted to string, unless it's an exact multiple of 'fizz' (when it returns the string "Fizz") or of 'buzz' (returns "Buzz") - or for multiples of both divisors, the combined string "FizzBuzz". >>> list(fizzbuzz(6, 2, 3)) ['1', 'Fizz', 'Buzz', 'Fizz', '5', 'FizzBuzz'] >>> list(fizzbuzz(6, 2, 4)) ['1', 'Fizz', '3', 'FizzBuzz', '5', 'Fizz'] ''' # accumulators tracking num % fizz and num % buzz fizz_acc = 0 buzz_acc = 0 for num in range(1, max_num + 1): fizz_acc += 1 buzz_acc += 1 result = "" if fizz_acc == fizz: fizz_acc = 0 result += "Fizz" if buzz_acc == buzz: buzz_acc = 0 result += "Buzz" yield result if result else str(num) def arg_or_input(argno, prompt): ''' Read a value from the 'argno'th command-line argument, or if there are fewer, use 'prompt' to input interactively. ''' try: return sys.argv[argno] except IndexError: return input(prompt) if __name__ == '__main__': import doctest if doctest.testmod()[0]: sys.exit(1) try: fizz = int(arg_or_input(1, "Enter the number to Fizz: ")) buzz = int(arg_or_input(2, "Enter the number to Buzz: ")) max_num = int(arg_or_input(3, "Enter the maximum number: ")) except ValueError: print("Inputs must be integers!", file=sys.stderr) sys.exit(1) if fizz <= 0 or buzz <= 0 or max_num <= 0: print("All inputs must be positive!", file=sys.stderr) sys.exit(1) for s in fizzbuzz(max_num, fizz, buzz): print(s)
getString(4, 2, 4) == "Fizz"when it should actually equal"FizzBuzz". This bug occurs whenfizzandbuzzare not coprime. \$\endgroup\$pylint's standards. Possiblypep8's too. \$\endgroup\$if num % fizz == 0 and num % buzz == 0:\$\endgroup\$