요약

코드는 요리 순서표와 비슷하다. 재료에 이름을 붙이고, 상황에 따라 다른 순서로 가고, 같은 일을 여러 번 하고, 자주 하는 일은 묶어서 이름을 붙인다. 코딩테스트에서는 이 순서표를 함수 하나로 쓰고, 마지막에 답을 돌려주면 끝난다. 화면에 찍거나 입력을 읽을 필요는 없다. 파이썬은 짧게 쓸 수 있는 대신 C 같은 언어보다 수십 배 느리다. 그래서 몇 번 반복하는지를 늘 신경 써야 한다.

예시로 보기

숫자가 짝수면 "Even", 홀수면 "Odd"를 돌려주는 답안이다. 프로그래머스 답안은 늘 이 모양이다.

def solution(num):          # 1. solution이라는 함수를 만든다. num이 들어오는 값이다
    if num % 2 == 0:        # 2. 2로 나눈 나머지가 0이면
        return "Even"       # 3. "Even"을 답으로 돌려주고 끝낸다
    else:                   # 4. 아니면
        return "Odd"        # 5. "Odd"를 돌려준다

채점하는 쪽은 solution(3), solution(4)처럼 함수를 불러서, 돌려받은 값이 정답과 같은지 본다. 그래서 답은 print로 찍는 게 아니라 return으로 돌려준다. 함수 이름과 괄호 안 이름은 문제에 적힌 그대로 둔다.

: 다음 줄을 안으로 들여 쓰는 것(보통 빈칸 4개)은 “이 줄은 위 줄에 딸린 줄”이라는 표시다. 들여쓰기가 어긋나면 코드가 돌아가지 않는다.

값과 변수

값에는 종류가 있다. 이 종류를 자료형(type)이라 부른다. 코딩테스트에서는 아래 다섯 가지면 거의 된다.

종류 예 알아 둘 점
int 정수 3, -7, 10**20 아무리 커도 된다. 넘쳐서 깨지는 일이 없다
float 실수 2.5, 1e9 소수 계산에 아주 작은 오차가 생길 수 있다
str 문자열 "abc", '가' 글자를 줄 세운 것. 리스트와 문자열에서 자세히 다룬다
bool 참·거짓 True, False 비교한 결과
None None “값이 없다”

변수는 값에 붙이는 이름표다. x = 5는 “5에 x라는 이름표를 붙인다”는 뜻이다. 수학의 “같다”가 아니다. 그래서 x = x + 1은 “지금 x에 1을 더한 값에 x라는 이름표를 다시 붙인다”가 된다. 줄여서 x += 1로 쓴다.

종류를 바꿀 때는 종류 이름을 함수처럼 쓴다. int("123")은 숫자 123, str(45)는 글자 "45"가 된다.

계산 기호

기호 뜻 예 결과
+ - * 더하기, 빼기, 곱하기 7 * 2 14
/ 나누기. 답은 늘 실수 7 / 2 3.5
// 몫 7 // 2 3
% 나머지 7 % 2 1
** 거듭제곱 2 ** 10 1024
== != 같다, 다르다 3 == 3 True
< <= > >= 크다, 작다 1 <= 2 < 3 True
and or not 그리고, 또는, 아니다 True and False False

몫과 나머지는 늘 짝이 맞는다. 몫에 나눈 수를 곱하고 나머지를 더하면 원래 수가 나온다. 식으로 쓰면 \(a = (a \,/\!/\, b) \cdot b + (a \,\%\, b)\)다1.

파이썬의 몫은 소수점을 그냥 떼는 게 아니라 더 작은 쪽으로 내린다. 그래서 -7 // 2는 -3이 아니라 -4다. 짝을 맞추려고 -7 % 2는 1이 된다. 양수로 나누면 나머지는 늘 0 이상이다. 그래서 음수도 num % 2 == 0으로 짝수인지 알 수 있다.

1 <= x < 5처럼 비교를 이어 쓸 수 있다. 1 <= x and x < 5와 같은 뜻이다.

조건문

if score >= 90:
    grade = "A"
elif score >= 80:     # 위 조건이 틀렸을 때만 본다
    grade = "B"
else:                 # 위가 다 틀렸으면
    grade = "C"

위에서부터 처음 맞는 한 곳만 실행한다. score = 95이면 "A"에서 멈추고 아래는 보지 않는다.

flowchart TD
    S["score를 받는다"] --> Q1{"score >= 90?"}
    Q1 -->|"예"| A["grade = A"]
    Q1 -->|"아니오"| Q2{"score >= 80?"}
    Q2 -->|"예"| B["grade = B"]
    Q2 -->|"아니오"| C["grade = C"]
    A --> E["if 문 다음 줄로"]
    B --> E
    C --> E

“예”로 빠지는 순간 나머지 질문은 건너뛰고 끝으로 간다. 그래서 elif의 질문은 앞 질문이 “아니오”일 때만 받는다2.

반복문

for는 “모음 안의 것을 하나씩 꺼내서 한 번씩”이다. 숫자 모음은 range로 만든다.

코드 나오는 값
range(5) 0, 1, 2, 3, 4 (5는 안 나온다)
range(1, 5) 1, 2, 3, 4
range(0, 10, 3) 0, 3, 6, 9
range(4, 0, -1) 4, 3, 2, 1
total = 0
for x in [3, 1, 4]:          # 리스트에서 하나씩 꺼내 x에 담는다
    total += x               # total: 3 → 4 → 8
for i, x in enumerate("ab"): # 번호도 같이 받는다: (0,'a'), (1,'b')
    print(i, x)
for a, b in zip([1, 2], [10, 20]):   # 두 모음을 나란히 꺼낸다: (1,10), (2,20)
    print(a + b)

while 조건:은 조건이 맞는 동안 계속 돈다. 몇 번 돌지 미리 모를 때 쓴다. break는 반복을 바로 멈추고, continue는 이번 바퀴만 건너뛴다.

n, steps = 27, 0
while n != 1:                          # n이 1이 될 때까지
    n = n // 2 if n % 2 == 0 else 3 * n + 1   # 한 줄로 쓴 조건: A if 조건 else B
    steps += 1

함수

def area(w, h=1):     # h를 안 주면 1로 친다(기본값)
    return w * h      # return을 만나면 값을 돌려주고 바로 끝난다

area(3, 4)   # 12
area(3)      # 3

return을 만나면 함수는 그 자리에서 끝난다. 반복문 안에서 return하면 남은 바퀴는 돌지 않는다. return이 없으면 None을 돌려준다.

함수 안에서 만든 변수는 함수 밖에서 보이지 않는다. 답안에 쓸 작은 함수는 solution 위나 안에 만들면 된다.

검증: 몫과 나머지의 짝을 음수를 포함한 무작위 정수 10,000쌍에서 확인했다. 표의 계산 결과, range가 내는 값, 예시 코드의 결과(total 8, 27이 1이 될 때까지 111번)도 확인했다 — 01_python-basics_verify.py

활용

  • 모든 풀이 문서의 코드는 이 문법에서 시작한다. 처음 나오는 문법은 그 풀이 문서의 5단계에서 줄마다 설명한다.
  • 자주 하는 실수:
    • print로 답을 내면 채점하는 쪽은 None을 받는다. 답은 return으로 돌려준다.
    • range(1, n)에는 n이 안 들어 있다. 1부터 n까지는 range(1, n + 1)이다.
    • 7 / 2는 3.5다. 몫이 필요하면 //를 쓴다. 답이 정수여야 하는데 /를 쓰면 2.0 같은 실수가 나가서 틀린다.
    • =는 이름표 붙이기, ==는 같은지 비교다.

연결

  • 다음 개념: 리스트와 문자열, 시간 복잡도로 방법 고르기
  • 연습: 짝수와 홀수
  • 양수로 나눌 때 //와 %가 주는 값은 나눗셈과 합동에 나오는 나눗셈 정리의 몫과 나머지다. 이 정리는 나머지가 0 이상이고 나누는 수보다 작은 (몫, 나머지) 짝이 딱 한 쌍뿐임을 보인다. 음수를 나눌 때 C·Java와 답이 다른 까닭도 거기서 다룬다.
  • for i in range(1, n + 1): total += i를 합의 기호로 쓰면 \(\sum_{i=1}^{n} i\)(\(\sum\)은 차례로 모두 더한다는 기호)이다. range(a, b)는 a ≤ b일 때 a부터 b − 1까지 b − a개를 낸다. 합의 기호와 항 개수 세는 법은 수열과 합의 기호에 있다.
  • float가 빠짐없이 정확히 담는 정수는 \(2^{53}\)까지다. 그래서 큰 정수를 /로 나누면 끝자리가 틀릴 수 있다. 정수 몫은 //로 구한다. 까닭은 거듭제곱과 지수법칙의 부동소수점 항목에 있다.
  • 참·거짓 값끼리 쓰면 and, or, not은 수학의 그리고(∧), 또는(∨), 아니다(¬)와 같다. 여러 조건을 묶은 if가 언제 참인지는 명제와 논리 연산의 진리표로 따진다. and의 앞 조건이 거짓이면 뒤를 보지 않는 단락 평가도 거기 있다.

확인 문제

C1 다음 코드가 끝나면 s는 얼마일까?
s = 0
for i in range(1, 10, 2):
    if i % 3 == 0:
        continue
    s += i

답: 13. i는 1, 3, 5, 7, 9다. 3과 9는 continue로 건너뛰니 1 + 5 + 7 = 13이다.

흔한 오답: 25(1~9의 홀수를 다 더함). continue가 그 바퀴의 남은 줄을 건너뛴다는 걸 놓친 것이다.

C2 -7 // 2가 -3이 아니라 -4인 까닭을 나머지 %와 묶어서 설명하라.

답: 파이썬은 “몫 × 나눈 수 + 나머지 = 원래 수”가 늘 맞게 하고, 양수로 나누면 나머지가 0 이상이 되게 정한다. -7 = (-4) × 2 + 1이니 몫은 −4, 나머지는 1이다. 몫을 −3으로 하면 나머지가 −1이 되어 이 약속이 깨진다.

C3 “1부터 n까지 더하려면 for i in range(n): total += i“라는 코드가 틀리는 가장 작은 n은?

답: n = 1. range(1)은 0 하나만 내서 합이 0인데, 답은 1이다. range(n)은 0부터 n − 1까지 돈다. 맞게 쓰면 range(1, n + 1)이다.

  1. Python 3 언어 레퍼런스 6.7 “Binary arithmetic operations”: 정수 나눗셈 //는 결과를 내림(floor)하고, x == (x//y)*y + (x%y)가 맞으며, %의 결과는 나누는 수와 부호가 같다. 문법 전반은 Python 3 공식 튜토리얼 3장 “An Informal Introduction to Python”, 4장 “More Control Flow Tools”. ↩

  2. 이 문서 ‘조건문’ 절의 score 예시 코드와 “위에서부터 처음 맞는 한 곳만 실행한다”는 설명을 순서도로 옮겼다(Python 3 공식 튜토리얼 4.1 if Statements). ↩