20.5 코드 단축하기

이번에는 코드를 매우 단축하여 FizzBuzz 문제를 풀어보겠습니다.

fizzbuzz_code_golf.py

for i in range(1, 101):
    print('Fizz' * (i % 3 == 0) + 'Buzz' * (i % 5 == 0) or i)
    # 문자열 곱셈과 덧셈을 이용하여 print 안에서 처리

실행 결과

1
2
Fizz
... (생략)
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz

이번 예제는 코드 골프 방식으로 작성해보았습니다. 코드 골프란 골프에서 따온 말인데, 실제 골프 경기는 더 적은 타수로 승부를 겨룹니다. 마찬가지로 코드 골프도 소스 코드의 문자 수를 최대한 줄여서 작성하는 놀이입니다(코드의 문자 수를 얼마나 줄일 수 있는지 겨루는 놀이일 뿐 실무에서 이런 방식으로 작성하면 나중에 작성자 본인을 포함해서 여러 사람이 고생하게 됩니다).

먼저 파이썬은 문자열을 곱하거나 더할 수 있죠? 문자열을 곱하면 문자열이 반복되고, 문자열을 더하면 두 문자열이 연결됩니다. 특히 문자열에 True를 곱하면 문자열이 그대로 나오고, False를 곱하면 문자열이 출력되지 않습니다(True는 1, False는 0으로 연산).

>>> 'Fizz' + 'Buzz'
'FizzBuzz'
>>> 'Fizz' * True
'Fizz'
>>> 'Fizz' * False
''

다음과 같이 문자열 곱셈을 이용하여 3의 배수일 때 'Fizz'를 출력합니다. i가 3의 배수이면 i % 3 == 0True이므로 'Fizz'가 출력되고, 3의 배수가 아니면 False이므로 'Fizz'가 출력되지 않습니다.

'Fizz' * (i % 3 == 0)

마찬가지로 'Buzz'도 문자열 곱셈을 이용하여 5의 배수일 때 출력합니다.

'Buzz' * (i % 5 == 0)

3과 5의 공배수일 때는 'FizzBuzz'를 출력해야 하는데 이때는 문자열 덧셈을 이용합니다. 즉, 3과 5의 공배수이면 'Fizz' * True + 'Buzz' * True가 되므로 'Fizz' + 'Buzz''FizzBuzz'를 출력합니다. 만약 한 쪽이 만족하지 않으면 덧셈할 문자열이 없으므로 'Fizz''Buzz'만 출력됩니다.

'Fizz' * (i % 3 == 0) + 'Buzz' * (i % 5 == 0)

3 또는 5의 배수가 아닐 때는 'Fizz' * False + 'Buzz' * False가 되고 결과는 빈 문자열 ''이 되는데, 이때는 or 연산자를 사용합니다. 빈 문자열은 False로 취급하고, i는 항상 1 이상의 숫자이므로 or로 연산하면 i만 남게 되어 숫자가 그대로 출력됩니다.

print('Fizz' * (i % 3 == 0) + 'Buzz' * (i % 5 == 0) or i)

이처럼 파이썬에서 연산자의 특성을 활용하면 코드의 길이를 짧게 줄일 수 있습니다. 하지만 코드가 읽기 어려워 진다면 이해하기 쉽도록 풀어서 작성하는 것이 좋습니다.

지금까지 반복문, 조건문, 논리 연산자, 나머지 연산자를 사용하여 FizzBuzz 문제를 풀어보았는데 간단하면서도 내용이 조금 까다로웠습니다. FizzBuzz 문제는 회사 면접 문제로 자주 사용된다고 했는데, 의외로 경력이 꽤 되는 프로그래머가 문제를 틀립니다. 보통 "이런 간단한 문제를 내다니"하면서 쉽게 보다가 3과 5의 공배수 처리 부분에서 실수를 하게 됩니다. 사실 FizzBuzz 문제는 프로그래밍 실력을 보는 것이 아니라 이해력을 보는 문제이기 때문입니다. 프로그래밍 실력보다 중요한 것이 요구 사항에 대한 이해력이라는 점 잊지 마세요.