0. 문제 의식의 출발
# 예제 코드 A
result = 0
def add(num):
global result
result += num
add(3)
print(result)
# return 사용하지 않음
# 결과값은 '3' 출력
# 예제 코드 B
result = 0
def add(num):
global result
result += num
return result
print(add(3))
# return 사용함
# 결과값은 '3' 출력
예제 A 코드와 B 코드는 동일한 기능이 구현되어 있다. 결과값도 같다. 차이는 리턴(return)의 사용 여부다. 나는 이 차이가 궁금해졌다. 과연 내가 진정으로 return 문의 의미를 알고 코드를 작성하는 것이 맞는지 의구심이 들었다. 이러한 의문은 많은 입문자들이 겪는 과정일 것이다. return 문 사용이 단순히 관행이 아니라 중요한 목적을 가지고 있다는 것을 이해하는 것은 매우 중요하다. 그런 의미에서 오늘은 파이선(python)에서 return 문을 사용하는 주요한 이유와 중요성에 대해서 공부해 보자.
1. 리턴(return)의 기본: 값을 반환한다
return 문은 함수가 어떤 값을 '반환'하도록 해준다. 쉽게 말해, 함수가 계산한 결과를 밖으로 내보낸다는 뜻이다.
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 출력: 8
여기서 add 함수는 두 수를 더한 결과를 리턴으로 반환한다. 이 값을 result에 저장하고 출력할 수 있다.
2. 함수(Function) vs 프로시저(Procedure): return의 역할
프로그래밍에서 함수(Function)와 프로시저(Procedure)는 코드를 구조화하고 모듈화하는 데 사용되는 핵심 개념이다. 이 두 개념은 겉보기에 비슷해 보일 수 있지만, 특히 리턴 문의 사용과 관련하여 중요한 차이점을 가지고 있다. 이러한 차이는 단순히 구문적인 것이 아니라, 프로그램의 설계 철학과 깊이 연괸되어 있다.
함수(Function)
함수(Function)는 주로 입력을 받아 처리하고 그 결과를 return 문을 통해 반환하는 것을 목적으로 한다. 이때 return 문은 함수의 핵심 요소로, 계산이나 처리의 결과를 함수 외부로 전달하는 역할을 한다. 함수에서 return의 사용은 단순히 값을 반환하는 것 이상의 의미를 가진다. 이는 함수의 실행을 즉시 종료하고, 호출자에게 제어권을 돌려주는 역할도 한다. 이러한 특성은 함수의 동작을 예측 가능하게 만들고, 재사용성을 높이는 데 기여한다. 예를 들어, 수학적 계산을 수행하는 함수에서 return은 그 계산의 결과를 명확하게 표현한다.
def add_numbers(a, b):
return a + b
result = add_numbers(3, 5)
print(f"3 + 5 = {result}") # 출력: 3 + 5 = 8
위 예제에서 add_numbers 함수는 두 숫자를 입력받아 그 합을 return 문을 통해 반환한다. 이 함수는 순수하게 입력에 기반한 결과를 생성하며, 외부 상태를 변경하지 않는 '순수 함수'의 특성을 보여준다.
프로시저(Procedure)
반면, 프로시저(Procedure)는 주로 특정 작업을 수행하는 것을 목적으로 하며, 반드시 값을 반환할 필요가 없다. 프로시저에서 return 문의 사용은 선택적이며, 사용되더라도 주로 작업의 완료나 상태를 나타내는 데 그친다. 프로시저는 종종 '부작용(side effect)'을 일으키는 작업, 즉 시스템의 상태를 변경하거나 외부와 상호작용하는 작업을 수행한다. 이러한 경우 return 문은 작업의 성공 여부를 나타내거나, 단순히 프로시저의 실행을 종료하는 데 사용될 수 있다.
def greet_user(name):
print(f"안녕하세요, {name}님!")
greet_user("Alice") # 출력: 안녕하세요, Alice님!
이 greet_user 프로시저는 사용자 이름을 입력받아 인사말을 출력한다. return 문을 사용하지 않으며, 대신 직접 콘솔에 출력하는 '부작용'을 수행한다.
3. State Machine(상태 기계): return의 활용
State Machine(상태 기계)은 시스템의 상태와 그 변화를 모델링하는 강력한 개념이다. 이는 복잡한 시스템의 동작을 단순화하고 예측 가능하게 만드는 데 매우 유용하다. State Machine에서 시스템은 항상 정의된 상태들 중 하나에 있으며, 특정 조건이나 이벤트에 따라 다른 상태로 전이된다. 이러한 상태 전이 로직을 구현할 때 return 문이 중요한 역할을 한다.
return 문은 State Machine에서 새로운 상태를 반환하는 데 사용된다. 이는 단순히 값을 반환하는 것 이상의 의미를 가진다. 상태 전이 함수에서 return을 사용함으로써, 우리는 현재 상태와 입력된 액션에 따른 시스템의 다음 상태를 명확하게 정의하고 반환할 수 있다. 이러한 방식은 상태 전이의 로직을 명확하게 표현하며, 시스템의 동작을 추적하고 이해하기 쉽게 만든다. 다음 예제를 통해 더 자세히 살펴보자.
def vending_machine(state, action):
if state == "대기" and action == "동전 투입":
return "준비"
elif state == "준비" and action == "음료 선택":
return "음료 제공"
elif state == "음료 제공" and action == "음료 수령":
return "대기"
else:
return state # 상태 변화 없음
current_state = "대기"
current_state = vending_machine(current_state, "동전 투입")
print(current_state) # 출력: 준비
current_state = vending_machine(current_state, "음료 선택")
print(current_state) # 출력: 음료 제공
이 예제에서 vending_machine 함수는 자판기의 State Machine을 구현한다. 함수는 현재 상태(state)와 수행된 동작(action)을 입력으로 받아, 새로운 상태를 return한다. 이 구조는 다음과 같은 중요한 특징을 가지고 있다.
- 상태 전이의 명확성: 각 조건문은 특정 상태와 동작의 조합에 대한 상태 전이를 명확히 정의한다. 예를 들어, "대기" 상태에서 "동전 투입" 동작이 발생하면 "준비" 상태로 전이된다.
- 불변성과 예측 가능성: 함수는 입력된 상태를 직접 변경하지 않고, 새로운 상태를 return한다. 이는 함수의 불변성을 보장하며, 동작을 예측 가능하게 만든다.
- 단일 책임 원칙: 이 함수는 오직 상태 전이 로직만을 담당한다. 실제 자판기의 동작(예: 음료 제공, 거스름돈 반환 등)은 이 함수의 책임이 아니다.
- 확장성: 새로운 상태나 동작을 추가하려면 단순히 새로운 조건문을 추가하면 된다. 이는 시스템을 쉽게 확장할 수 있게 해준다.
- 디버깅 용이성: 각 상태 전이가 명확히 정의되어 있어, 시스템의 동작을 쉽게 추적하고 디버그할 수 있다.
4. return을 사용해야 하는 이유
프로그래밍에서 return 문의 사용은 단순한 관행을 넘어서는 중요한 의미를 갖는다. return을 적절히 활용함으로써 얻을 수 있는 주요 이점은 코드의 명확성 향상, 재사용성 증대, 그리고 테스트 용이성 개선이다. 이러한 이점들은 개별적으로도 중요하지만, 함께 작용하여 전체적인 코드 품질과 유지보수성을 크게 향상시킨다.
- 명확성: 함수의 목적과 결과를 분명히 알 수 있다.
- 재사용성: 반환된 값을 다른 곳에서 사용할 수 있다.
- 테스트 용이성: 함수의 결과를 쉽게 확인하고 테스트할 수 있다.
5. 결론: return은 단순한 관행이 아니다
return은 단순한 관행이 아니라, 함수의 결과를 명확히 하고 코드의 흐름을 제어하는 중요한 도구이다. 함수에서는 계산 결과를 반환하고, 프로시저에서는 작업의 완료를 알리며, State Machine에서는 새로운 상태를 표현하는 데 사용된다. return을 적절히 사용하면 코드가 더 명확해지고, 재사용성과 테스트 용이성이 높아진다.
글을 마치며.
return의 진정한 가치는 이를 사용하는 프로그래머의 사고방식에 있는 생각이 든다. return의 사용을 고민한다는 것은 곧 함수의 목적, 책임의 범위, 코드의 구조에 대해 깊이 생각한다는 의미이다. 이는 단순히 코드를 작성하는 것을 넘어, 문제를 효과적으로 모델링하고 해결책을 설계하는 능력의 성장을 나타낸다. 프로그래밍을 하면서 return의 사용을 고민하는 것만으로도 이 글을 읽고 있는 당신은 이미 좋은 프로그래머다. 파이팅 하자.
'TIL' 카테고리의 다른 글
위상 정렬(Topological Sort) (4) | 2024.09.22 |
---|---|
알고리즘 그래프 탐색 - DFS(깊이 우선 탐색) (1) | 2024.09.22 |
알고리즘 그래프 탐색 - BFS(너비 우선 탐색) (0) | 2024.09.21 |
[TIL] 그래프 1편 - 그래프 정의, 특징, 종류, 구성 요소 (2) | 2024.09.20 |
[TIL] 컴퓨터 시스템 요약 - 1장. 컴퓨터 시스템으로의 여행 (1편) (4) | 2024.09.18 |