하리Hari

9. 함수 (기능 만들기)

자주 쓰는 코드에 이름을 붙여 묶고, 필요할 때 불러 써요.

이 장에서 배울 것

  • 함수 만들기(만들자)와 부르기(실행하자)
  • 재료(인자) 넘기기와 결과 돌려받기(돌려주자)
  • 출력과 돌려주기의 차이
  • 함수 안과 밖의 이름표, 기본값, 재귀

함수란?

같은 코드를 여러 곳에서 쓰다 보면 복사해 붙이게 되죠. 그 코드를 한 번 묶어서 이름을 붙여 두고, 필요할 때마다 이름으로 부르면 편해요. 이렇게 이름 붙인 코드 묶음을 함수라고 해요. <문자로>처럼 꺾쇠로 쓰는 것들이 모두 함수예요. 이제 직접 만들어 봐요.

만들고 부르기

<인사하기>를 만들자 ():
    "안녕하세요!"를 출력하자
    "오늘도 좋은 하루 보내세요."를 출력하자

<인사하기>()를 실행하자
<인사하기>()를 실행하자
  • <인사하기>를 만들자 (): — <인사하기>라는 함수를 만들어요. 들여 쓴 줄들이 함수가 할 일이에요.
  • 만들기만 해서는 실행되지 않아요. <인사하기>()를 실행하자로 불러야 실행돼요.
  • 두 번 불렀으니 인사가 두 번 나와요.

재료 넘기기 (인자)

괄호 안에 이름표를 적으면, 부를 때 넘긴 값이 그 이름표에 담겨요. 이 값을 인자라고 해요.

<인사하기>를 만들자 ('이름'):
    틀"{'이름'}님, 안녕하세요!"를 출력하자

<인사하기>("하리")를 실행하자
<인사하기>("두리")를 실행하자

인자가 여러 개면 쉼표로 나열해요. 부를 때도 같은 순서로 넘겨요.

<소개하기>를 만들자 ('이름', '나이'):
    틀"{'이름'}은(는) {'나이'}살이에요."를 출력하자

<소개하기>("하리", 20)를 실행하자

결과 돌려받기: 돌려주자

함수가 계산한 결과를 부른 곳으로 돌려줄 수 있어요. 돌려받은 값은 이름표에 담거나 바로 쓸 수 있어요.

<더하기>를 만들자 ('가', '나'):
    ('가' + '나')를 돌려주자

'합'을 <더하기>(10, 20)으로 정하자
'합'을 출력하자
(<더하기>(1, 2) * 10)을 출력하자

30과 30이 나와요. 두 번째 줄에서 <더하기>(1, 2)가 3이 되고, 거기에 10을 곱했어요.

돌려주자를 만나면 함수는 그 자리에서 끝나요. 그 아래 줄은 실행되지 않아요. 그래서 조건에 따라 일찍 돌려줄 수 있어요.

<등급>을 만들자 ('점수'):
    만약 ('점수'가 90 이상이다) 라면:
        "A"를 돌려주자
    만약 ('점수'가 80 이상이다) 라면:
        "B"를 돌려주자
    "C"를 돌려주자

(<등급>(95))를 출력하자
(<등급>(85))를 출력하자
(<등급>(50))를 출력하자

출력하기 vs 돌려주기

초보자가 가장 많이 헷갈리는 부분이에요.

출력하자 돌려주자
하는 일 화면에 보여 줘요 부른 곳에 값을 건네요
그 값으로 계속 계산 할 수 없어요 할 수 있어요
<두배출력>을 만들자 ('x'):
    ('x' * 2)를 출력하자

<두배돌려주기>를 만들자 ('x'):
    ('x' * 2)를 돌려주자

'가'를 <두배출력>(5)로 정하자
'나'를 <두배돌려주기>(5)로 정하자
'가'를 출력하자
'나'를 출력하자

10(함수 안의 출력), 비어있음, 10이 나와요. <두배출력>은 화면에 보여 주기만 하고 아무것도 돌려주지 않아서 '가'에는 비어있음이 담겼어요. 결과를 다른 곳에서 쓰려면 돌려주자 를 쓰세요.


함수 안과 밖의 이름표

  • 함수 안에서 만든 이름표는 함수가 끝나면 사라져요. 밖에서 쓸 수 없어요.
  • 맨 바깥(최상위)에서 만든 이름표는 함수 안에서도 읽고 바꿀 수 있어요.
'점수'를 10으로 정하자

<점수올리기>를 만들자 ():
    '보너스'를 5로 정하자
    '점수'에 '보너스'를 더하자

<점수올리기>()를 실행하자
'점수'를 출력하자

15가 나와요. '보너스'는 함수 안에서만 있었으니, 밖에서 '보너스'를 출력하자라고 쓰면 오류가 나요.

다만 함수가 바깥 이름표를 바꾸면 어디서 값이 바뀌었는지 찾기 어려워져요. 가능하면 인자로 받고 결과를 돌려주는 모양이 좋아요.

<보너스더하기>를 만들자 ('점수'):
    ('점수' + 5)를 돌려주자

'내점수'를 10으로 정하자
'내점수'를 <보너스더하기>('내점수')로 정하자
'내점수'를 출력하자

목록과 사전을 넘기면

7장에서 본 것처럼, 목록과 사전은 다른 이름표에 담아도 같은 묶음을 가리켜요. 함수에 넘길 때도 같아서, 함수 안에서 목록을 바꾸면 밖의 목록도 바뀌어요. 숫자와 문자열은 함수 안에서 바꿔도 밖은 그대로예요.

<항목추가>를 만들자 ('목록'):
    '목록'에 "새 항목"을 추가하자

<숫자바꾸기>를 만들자 ('수'):
    '수'에 100을 더하자

'내목록'을 ["처음"]으로 정하자
'내숫자'를 1로 정하자
<항목추가>('내목록')를 실행하자
<숫자바꾸기>('내숫자')를 실행하자
'내목록'을 출력하자
'내숫자'를 출력하자

[처음, 새 항목]과 1이 나와요.


인자의 기본값

인자 뒤에 = 값을 쓰면, 부를 때 그 인자를 빼먹어도 기본값이 들어가요.

<인사하기>를 만들자 ('이름', '말' = "안녕하세요"):
    틀"{'이름'}님, {'말'}!"을 출력하자

<인사하기>("하나")를 실행하자
<인사하기>("하나", "반가워요")를 실행하자

하리에는 같은 이름으로 인자만 다르게 함수를 여러 번 만드는 오버로딩이 없어요. 함수 이름은 한 곳에 하나뿐이라, 같은 이름을 또 만들면 프로그램이 실행되기 전에 구문 오류가 나요. 인자가 있을 때와 없을 때를 나누고 싶다면 위처럼 기본값을 쓰거나 다른 이름을 붙여 주세요.

<인사하기>를 만들자 ():
    "안녕하세요!"를 출력하자

<인사하기>를 만들자 ('이름'):
    틀"{'이름'}님, 안녕하세요!"를 출력하자

타입 붙이기 (선택)

인자와 돌려주는 값에도 타입을 붙일 수 있어요. 붙이면 잘못된 값이 들어가거나 나올 때 바로 알려 줘요.

[숫자]를 돌려주는 <넓이>를 만들자 ([숫자]인 '가로', [숫자]인 '세로'):
    ('가로' * '세로')를 돌려주자

(<넓이>(3, 4))를 출력하자
[숫자]를 돌려주는 <나이>를 만들자 ():
    "스물"을 돌려주자

<나이>()를 출력하자

“‘나이’ 함수는 ‘숫자’ 타입을 돌려줘야 하는데 ‘문자열’ 값을 돌려줬어요.” 가 나와요. 아무것도 돌려주지 않고 끝나는 함수(비어있음)는 어떤 타입이어도 통과해요.


함수가 자기 자신을 부르기 (재귀)

함수 안에서 같은 함수를 다시 부를 수 있어요. 이것을 재귀라고 해요. 큰 문제를 같은 모양의 작은 문제로 나눌 때 써요. 5의 팩토리얼(5 × 4 × 3 × 2 × 1)은 “5 × (4의 팩토리얼)“이에요.

<팩토리얼>을 만들자 ('n'):
    만약 ('n'이 1 이하이다) 라면:
        1을 돌려주자
    ('n' * <팩토리얼>('n' - 1))를 돌려주자

(<팩토리얼>(5))를 출력하자

재귀에는 멈추는 조건이 꼭 있어야 해요. 위에서는 'n'이 1 이하이면 더 부르지 않고 1을 돌려줘요. 멈추는 곳이 없으면 호출이 끝없이 쌓이다가, 10000단계를 넘으면 하리가 RecursionError로 막아 줘요.


자주 하는 실수

1. 만들기만 하고 부르지 않기

만들자는 함수를 준비만 해요. 실행하려면 <이름>()를 실행하자로 불러야 해요.

2. 출력과 돌려주기 혼동

함수의 결과를 이름표에 담았는데 비어있음이 나온다면, 함수 안에서 출력하자만 하고 돌려주자를 안 했는지 확인하세요.

3. 인자 개수가 다르기

필요한 인자를 빼먹거나 너무 많이 넘기면 오류가 나요.

<두배>를 만들자 ('수'):
    ('수' * 2)를 돌려주자

(<두배>())를 출력하자

“‘수’ 인자가 필요해요.” 가 나와요. 너무 많이 넘기면 “인자가 너무 많아요.” 가 나와요.

4. 괄호 빼먹기

함수를 부를 때는 인자가 없어도 ()를 꼭 붙여요. <인사하기>()를 실행하자.


정리

하고 싶은 일 쓰는 법
함수 만들기 <이름>을 만들자 ('인자1', '인자2'):
부르기 (결과 안 씀) <이름>(값1, 값2)를 실행하자
결과 받기 'x'를 <이름>(값)으로 정하자
결과 돌려주기 값을 돌려주자 (그 자리에서 함수 끝)
기본값 ('말' = "안녕")
타입 [숫자]를 돌려주는 <이름>을 만들자 ([숫자]인 'x'):

연습 문제

1. 섭씨온도를 받아 화씨온도를 돌려주는 <화씨로>를 만들어 보세요. (화씨 = 섭씨 × 9 / 5 + 32)

정답 예시
<화씨로>를 만들자 ('섭씨'):
    ('섭씨' * 9 / 5 + 32)를 돌려주자

(<화씨로>(100))를 출력하자
(<화씨로>(0))를 출력하자

212와 32가 나와요.

2. 숫자 목록을 받아 평균을 돌려주는 <평균>을 만들어 보세요. (8장의 “모두 더하기”를 함수 안에서 써요.)

정답 예시
<평균>을 만들자 ('수들'):
    '합'을 0으로 정하자
    '수들'의 '수'마다 반복하자:
        '합'에 '수'를 더하자
    ('합' / '수들'의 '길이')를 돌려주자

(<평균>([80, 90, 100]))를 출력하자

3. 숫자가 짝수이면 참, 아니면 거짓을 돌려주는 <짝수인가>를 만들고, 1부터 5까지 각각 결과를 출력해 보세요.

정답 예시
<짝수인가>를 만들자 ('수'):
    ('수' % 2가 0과 같다)를 돌려주자

1부터 5까지 반복하자 ('i'):
    틀"{'i'}: {<짝수인가>('i')}"를 출력하자

다음 장에서는 오류가 나도 프로그램이 멈추지 않게 오류를 잡는 법을 배워요.

놀이터
결과
코드를 작성하고 '실행' 버튼을 눌러보세요.