06-2 함수와 반환 알아보기
윤혜민·박현규 · 29 / 30 절지금까지 함수는 어떻게 만드는지, 함수 헤더와 함수 본문이 어떤 구성인지, 함수 본문의 코드 블록을 저장해두었다가 실행할 수 있는지, 함수를 실행할 때 바꿔 적용할 값을 위한 매개변수와 같은 기본 특징을 공부했습니다. 하지만 제가 하나 이야기하지 않은 것이 있습니다. 바로 반환이라는 겁니다. 반환을 지금 이야기하는 이유는 함수의 반환을 처음 공부하면 ‘별 거 아닌 개념이구나’ 싶다가도 함수들이 얽히는 과정에 다다르면 ‘이거 조금 난해하다’라고 생각하기 쉬운 쉽고도 어려운 개념이기 때문입니다.
반환이 뭔가요?
반환이란 함수가 어떤 값을 뱉는 것입니다. 우리 주변에서 쉽게 볼 수 있는 함수의 반환은 아주 많습니다. 예를 들어 밥솥은 쌀과 물을 넣고 취사 버튼을 누르면 밥을 뱉습니다. 이를 함수의 개념과 반환에 빗대어 정리하면 다음과 같습니다.
밥솥의 내솥 : 매개변수
쌀과 물 : 함수 실행 시 들어가는 인수
밥짓는 과정 : 함수 본문의 코드 블록 실행
완성한 밥 : 함수가 반환한 값
함수는 return이라는 키워드로 반환을 할 수 있습니다. 여기서 반환하는 건 값이 될 수도 있고, 또 다른 함수일 수도 있습니다. 작업을 마치고 아무 반환도 하지 않을 수도 있습니다.
함수는 여러 값을 반환할 순 없습니다
파이썬의 함수는 여러 값을 반환할 수 없습니다. 여기서 파이썬 입문자가 많이 헷갈려하는 건 return 문에 쉼표로 값을 여러 개 나열해도 문제가 없음을 알았을 때입니다. 이건 함수가 여러 값을 반환해서가 아니라 파이썬이 쉼표로 나열한 값들을 튜플{tuple}이라는 하나의 덩어리로 묶어서 반환하기 때문입니다. 어쨌든 함수는 하나의 값만 반환하거나 아예 반환하지 않습니다. 다음 코드는 리스트 [3, 1, 4, 1, 5, 9, 2, 6]을 매개변수로 받아서 최솟값과 최댓값을 튜플로 반환하는 함수입니다.
def get_min_max(numbers):
return min(numbers), max(numbers)
result = get_min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(result)
print(type(result))
[실행 결과]
(1, 9)
<class 'tuple'>
실행 결과를 보면 1, 9가 아니라 (1, 9)입니다. 튜플로 반환했으니 1개의 값을 반환한 겁니다. 좀 말장난 같이 보이겠지만 이 미묘한 차이를 받아들여야 합니다.
헷갈리는 반환
가끔 다음과 같은 코드를 입력하여 실행하면서 ‘함수를 실행해서 뭔가가 출력이 됐는데 반환이 된 거 아니냐’라고 질문하는 사람들이 있습니다. 앞에서 작성한 코드를 다시 봅시다.
>>> def greet(name):
>>> print(f"안녕하세요! <span class="mark">{name} 님!</span>")
```
>>> greet(<span class="mark">"요즘"</span>)
```
```실행 결과
안녕하세요! 요즘 님!
```
greet( ) 함수를 실행했을 때 인삿말이 출력된 것을 보고 ‘인삿말을 반환했다’라고 오해하는 겁니다. 하지만 반환은 함수의 return을 통해 값을 돌려주는 것이지 무언가를 출력하는 것과는 전혀 다른 개념입니다. 반환은 꼭 return 키워드와 함께 사용해야 동작합니다. 값을 출력하는 것과 값을 반환하는 것을 ‘동일하다’라고 오해하지 않기 바랍니다. 만약 인삿말을 반환하는 코드로 변경하려면 다음과 같이 말 그대로 ‘인삿말을 return으로 반환하는 코드’를 작성해야 합니다.
```
>>> def greet(name):
>>> <span class="mark">return "안녕하세요! " + "name 님!"</span>
>>> print(greet("바로"))
```
```실행 결과
안녕하세요! 요즘 님!
```
이제 조금 더 구체적인 예를 통해 함수와 반환을 이해해보겠습니다. 상상을 쉽게 할 수 있도록 가래떡 공장의 기계를 함수에 비유하며 설명하고 중간중간 코드를 작성하고 실행해보면서 함수의 반환을 이해해보겠습니다.
가래떡 공장으로 이해하는 함수와 반환
예를 들어 여러분이 가래떡을 만드는 공장을 운영한다면 이런 기계가 필요할 겁니다.

쌀을 깨끗하게 씻는 기계 : 쌀과 물을 넣으면 쌀을 깨끗하게 씻어 내보내준다.
쌀을 찌는 기계 : 깨끗한 쌀을 넣으면 이것을 쪄서 밥으로 만들어 내보내준다.
밥을 치대는 기계 : 밥을 넣으면 밥을 치대서 반죽으로 내보내준다.
가래떡 형태로 만드는 기계 : 반죽을 넣으면 가래떡 형태로 만들어 내보내준다.
각 기계에는 넣어야 할 재료 항목이 정해져있습니다. 기계 전체를 함수라고 보면 ➊ 기계가 재료를 받기 위해 만든 투입구가 매개변수입니다. ➋ 그리고 실제로 넣는 재료는 인수입니다. ➌ 마지막으로 기계가 뱉어낸 결과물이 반환값입니다. 다음은 첫 번째 기계인 ‘쌀을 깨끗하게 씻는 기계’입니다. 그림을 봅시다.

쌀을 깨끗하게 씻는 기계는 ➊ 매개변수로 쌀과 물을 받는 투입구가 있습니다. ➋ 그리고 실제로 쌀과 물이 들어갑니다. ➌ 그리고 이 기계는 깨끗한 쌀을 반환합니다. 이를 함수로 형상화하면 다음과 같이 코드를 작성해볼 수 있습니다.
```
# 깨끗하게 쌀을 씻는 기계 정의
def wash_rice(rice, water):
print(f"{rice}을 {water}로 씻고 있습니다.")
return "깨끗한 쌀"
```
이렇게 함수를 정의하고 실제로 기계를 가동하려면 함수를 다음과 같이 호출해야 합니다.
```
# 깨끗하게 쌀을 씻는 기계 호출
result1 = wash_rice("씻지 않은 쌀", "깨끗한 물")
```
```실행 결과
씻지 않은 쌀을 깨끗한 물로 씻고 있습니다.
```
실행 결과에 보이는 ‘씻지 않은 쌀을 깨끗한 물로 씻고 있습니다.’는 wash_rice("씻지 않은 쌀", "깨끗한 물")의 함수 본문의 print( )가 출력된 겁니다. 함수의 반환값은 return으로 반환한 "깨끗한 쌀"이라는 문자열입니다. 반환값은 result1에 저장했네요. 이렇게 함수는 함수 본문에서 특정 작업을 하고 return 키워드로 값을 내보냅니다. 받은 값은 변수에 저장해서 또 어딘가에 사용하죠. 이처럼 우리 주변에서 볼 수 있거나 상상하기 쉬운 기계들을 연상하면 함수를 쉽게 이해할 수 있습니다. 비유를 통해 함수와 반환을 이해했으니 좀 더 실용적인 실습 예제를 통해 함수와 반환을 연습해봅시다.
[Note] 이후 과정도 함수의 매개변수와 return을 생각하며 그림과 함께 생각해보세요. 아마 어렵지 않을 겁니다.
함수 정의와 호출 연습하기
[연습 01] 인삿말을 만들어주는 함수
다음은 인삿말을 만들어주는 함수입니다. 복습 차원에서 함수를 만들고 함수를 호출해봅시다.
def make_greeting(name):
message = f"안녕하세요, {name}님! 오늘도 좋은 하루 보내세요."
return message
바로_인사 = make_greeting("바로")
print(바로_인사)
[실행 결과]
안녕하세요, 바로님! 오늘도 좋은 하루 보내세요.
[연습 02] 점수를 평가하고 학점을 반환하는 함수
이번에는 함수에 if문을 조합해서 점수를 매개변수로 받아 평가하고 학점을 반환하는 함수를 만들어보겠습니다.
def evaluate_score(score):
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "D"
return grade
yozm_math = evaluate_score(92)
yozm_eng = evaluate_score(87)
yozm_sci = evaluate_score(76)
print(f"바로의 수학 등급: {yozm_math}")
print(f"바로의 영어 등급: {yozm_eng}")
print(f"바로의 과학 등급: {yozm_sci}")
[실행 결과]
바로의 수학 등급: A
바로의 영어 등급: B
바로의 과학 등급: C
evaluate_score( ) 함수는 점수를 받아서 if문으로 학점을 평가한 후 grade 변수에 담고 return grade를 통해 학점을 반환합니다. 이렇게 점수를 평가해서 학점을 만들어주는 함수를 만들면 여러번 호출해서 평가한 결과를 쉽게 사용할 수 있습니다.
[연습 03] 할인 가격을 계산해주는 함수
이번에는 함수가 계산 결과를 반환하고, 그 반환값을 다시 다른 함수의 입력으로 사용하는 예제를 살펴보겠습니다. 다음 코드를 입력해서 실행해보면 여러 함수를 연결해서 사용하는 방법을 알 수 있을 겁니다.
def apply_discount(price, discount_rate):
discount_amount = price * discount_rate
return discount_amount
def calculate_final_price(price, discount_amount):
final_price = price - discount_amount
return final_price
# 바로가 구매하려는 책 가격
book_price = 20000
# 20% 할인 적용
discount = apply_discount(book_price, 0.2)
print(f"할인 금액: {discount}원")
# 최종 가격 계산
final = calculate_final_price(book_price, discount)
print(f"최종 가격: {final}원")
[실행 결과]
할인 금액: 4000.0원
최종 가격: 16000.0원
첫 번째 함수 apply_discount( )는 원래 가격과 할인율을 받아서 할인 금액을 계산하여 반환합니다. 두 번째 함수 calculate_final_price( )는 원래 가격과 할인 금액을 받아서 최종 가격을 계산하여 반환합니다.
함수가 반환한 값을 다시 함수에 사용하기
함수의 반환값을 다른 함수의 인수로 바로 전달할 수도 있습니다. 예를 들어 쌀을 씻는 함수와 밥을 짓는 함수의 관계를 생각해보면 쌀을 씻는 함수의 반환값인 "씻은 쌀"이 그대로 밥을 짓는 함수의 인수로 들어가면 자연스럽겠죠. 이처럼 함수가 반환한 값이 다른 함수의 인수에 적합하다면 다음과 같이 코드를 작성해도 됩니다.
def wash_rice(rice):
print(f"{rice}을 깨끗하게 씻고 있습니다...")
return "깨끗한 쌀"
def steam_rice(rice):
print(f"{rice}을 찌고 있습니다...")
return "밥"
# 방법 1: 중간 변수 사용
step1 = wash_rice("씻지 않은 쌀")
step2 = steam_rice(step1)
print(f"최종 결과: {step2}\n")
# 방법 2: 함수를 직접 연결
result = steam_rice(wash_rice("씻지 않은 쌀"))
print(f"최종 결과: {result}")
[실행 결과]
씻지 않은 쌀을 깨끗하게 씻고 있습니다...
깨끗한 쌀을 찌고 있습니다...
최종 결과: 밥
씻지 않은 쌀을 깨끗하게 씻고 있습니다...
깨끗한 쌀을 찌고 있습니다...
최종 결과: 밥
함수는 값만 반환할까?
여기서 조금 이상한 말을 해보겠습니다. 분명 저는 처음에 함수는 값만 반환한다고 이야기하지 않았습니다. "밥"이나 12와 같은 문자열 숫자만 반환하는 것이 아니라 함수가 함수를 반환할 수도 있다고 했습니다. 예를 들어 여러분이 지금 당장 함수를 실행하고 싶지는 않지만 ‘어떤 형태의 함수를 만들고 싶다’라는 생각만 있다면 어떨까요? 쉽게 말해서 무슨 숫자를 넣어도 3만 곱해주는 함수, 무슨 숫자를 넣어도 10만 곱해주는 함수를 만들고 싶다면 어떨까요? 대부분 구성이 같지만 일부만 다르게 생긴 함수를 만들고 싶을 수도 있습니다.
[Note] 억지로 실생활과 연관을 짓는다면 기계를 만드는 기계를 생각해봅시다. 예를 들어 "보리"라고 적힌 종이를 넣으면 보리밥을 지어주는 밥솥을 만드는 기계, "쌀"이라고 적힌 종이를 넣으면 쌀밥을 지어주는 밥솥을 만드는 기계를 생각해봅시다.
일단 다음 코드를 작성해서 실행해봅시다.
def make_multiplier(n):
def multiplier(x):
return x * n
return multiplier
times3 = make_multiplier(3)
times5 = make_multiplier(5)
print(times3(10))
print(times5(10))
[실행 결과]
30
50
함수의 형태를 자세히 보면 make_multiplier( )의 내부에서 다시 multiplier( ) 함수를 정의하고 있습니다. 그리고 반환하는 값은 어떤 계산 결괏값이 아니라 multiplier라는 함수의 이름입니다. 그래서 make_multiplier( ) 함수를 실행하면 인수로 전달한 값만 곱해주는 multiplier( ) 함수를 만들 수 있습니다. 아마 이쯤되면 머리가 좀 복잡해져서 생각을 그만두고 싶을 수도 있습니다. 하지만 가만 생각해보면 별게 아닙니다.
함수를 반환하는 함수의 실행 과정 차분하게 뜯어보기
예를 들어 make_multiplier(3)를 실행하면 오직 3만 곱해주는 함수가 나오는 과정을 차분하게 생각해봅시다. 다음을 실행하면 어떤 일이 일어날까요?
times3 = make_multiplier(3)
make_multiplier( ) 함수의 형태를 떠올려보면 결국은 x * 3을 반환하는 함수를 반환한다는 걸 알 수 있습니다. 그 과정을 그림으로 나타내면 다음과 같습니다. 그림이 좀 복잡하니 차분하게 그림과 설명을 읽어봅시다.

➊ make_multiplier(3)을 실행하면 ➋ 인수 3은 함수 make_multiplier( ) 내부로 전달이 됩니다. ➌ 인수는 make_multiplier( )가 반환할 함수인 muliplier( )에서 반환값으로 사용됩니다. ➍ 그러면 결국 return multiplier는 3을 곱하는 함수 muliplier( )를 반환하고 ➎ times3 변수에는 그 함수가 들어오겠죠!
<1:1 코칭> 이렇게까지 함수의 반환을 설명하는 이유?
아마 이쯤되면 ‘함수의 반환을 뭐 이렇게까지 설명하나’ 싶을 수 있습니다. 제가 이렇게까지 함수의 반환을 설명하는 이유는 함수의 반환이라는 콘셉트를 여러분이 넓은 범위에서 이해하기 바라는 마음입니다. 보통 문법서에서는 함수의 반환을 설명할 때 12와 같은 숫자나 "바로"와 같은 문자열만 반환하는 내용으로 설명합니다. 하지만 실제로 여러분이 나중에 볼 코드는 그렇게 값만 반환하지 않습니다. 물론 파이썬의 문법을 가볍게 익히려는 목적이면 이 설명이 무겁게 느껴질 수도 있겠습니다만 어쨌든 함수의 반환이라는 콘셉트를 이해하는데는 이만한 집중력을 요하는 예를 소개하는 것이 좋겠다 싶어 소개하였습니다.
함수를 반환하는 함수 호출 연습하기
이제 2가지 예제를 통해서 함수를 반환하는 함수 호출을 연습하며 마무리하겠습니다. 파이썬 문법을 이제 막 공부하는 시점에서 자주 사용할 정도의 코드 예는 아니지만 함수의 호출과 함수 반환을 연습한다는 관점에서 작성하고 실행하며 공부해보기 바랍니다.
[연습 01] 인삿말을 만들어주는 함수를 반환하는 함수
앞에서 함수의 기초를 공부할 때 인삿말을 만들어주는 함수를 만들었습니다. 약간 말장난 같지만 인삿말을 만들어주는 함수를 만들어주는 함수는 어떨까요? 예를 들어서 OO에게 인사한다라는 목적은 같지만 인삿말의 형태가 다른 상황을 생각해보면 됩니다.
“반갑습니다! 바로님!”
“안녕~ 요즘아!”
def make_greeting(greeting_word):
def greet(name):
return f"{greeting_word} {name}!"
return greet
formal_greeter = make_greeting("반갑습니다!")
casual_greeter = make_greeting("안녕~")
print(formal_greeter("바로님"))
print(casual_greeter("요즘아"))
[실행 결과]
반갑습니다! 바로님!
안녕~ 요즘아!
make_greeting( ) 함수는 인삿말을 매개변수 greeting_word로 받아서 **그 인사말로 누군가에게 인사하는 함수 formal_greeter( )**를 반환합니다. 인삿말의 형태를 정해서 formal_greeter, casual_greeter 변수에 저장한다고 생각하면 됩니다. 결국은 formal_greeter 변수에 저장한 함수는 "반갑습니다!"로 격식있게 인사하는 함수가 되고, casual_greeter 변수에 저장한 함수는 "안녕~"으로 친근하게 인사하는 함수가 됩니다.
[연습 02] 계산기를 만들어주는 함수
이번에는 사칙연산을 수행하는 계산기 함수를 만들어보겠습니다. make_calculator( ) 함수는 연산자를 받아서 해당 연산을 수행하는 함수를 반환합니다. 이렇게 하면 덧셈, 뺄셈, 곱셈, 나눗셈 함수를 각각 간편하게 만들 수 있습니다. 다음 코드를 입력해서 실행해보면 하나의 함수로 여러 종류의 계산 함수를 만들 수 있다는 것을 알 수 있을 겁니다.
def make_calculator(operation):
def calculate(a, b):
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
elif operation == "divide":
return a / b
return calculate
add_func = make_calculator("add")
multiply_func = make_calculator("multiply")
print(add_func(15, 5))
print(multiply_func(15, 5))
print(add_func(100, 25))
[실행 결과]
20
75
125
make_calculator("add")를 호출하면 덧셈을 수행하는 함수가 반환됩니다. 그래서 add_func(15, 5)는 15 + 5 = 20을 계산하고, multiply_func(15, 5)는 15 × 5 = 75를 계산합니다. 한 번 만든 함수는 계속해서 재사용할 수 있어서 add_func(100, 25)처럼 다른 숫자로도 계산할 수 있습니다.
