01. 함수 (자판기 만들기)
"함수는 자판기입니다. 재료(Input)를 넣으면 결과물(Output)이 나옵니다. 더 중요한 건, 하나의 구체적인 행동(동사)을 포장해서 이름표를 붙이는 것입니다."
1. 함수의 구조 (Mental Model)
수학의 함수 \(f(x) = x + 1\) 과 구조가 똑같습니다.
graph LR
Input["재료: 콩, 물"] --> Machine["자판기: make_coffee"]
Machine --> Output["결과: 커피"]
style Input fill:#e1f5fe,stroke:#01579b
style Machine fill:#fff9c4,stroke:#fbc02d
style Output fill:#e8f5e9,stroke:#2e7d32
def make_coffee(bean, water): # 재료 (Parameter/매개변수)
"""
커피콩과 물을 받아서 커피를 만드는 함수입니다.
(이런 설명을 'Docstring'이라고 합니다)
"""
result = bean + water # 로직 (Body)
return result # 결과물 (Return Value)
2. Return vs Print (가장 많이 하는 실수)
초보자가 함수를 만들 때 가장 많이 하는 실수는 return 대신 print를 쓰고 끝내는 것입니다.
graph TD
subgraph Print["❌ Print (증발)"]
F1[함수 실행] -->|"화면에 출력"| Screen["🖥️ 화면"]
Screen -.->|"데이터 사라짐"| Void(("허공"))
end
style Print fill:#ffebee,stroke:#c62828
🆚
graph TD
subgraph Return["✅ Return (배달)"]
F2[함수 실행] -->|"값을 반환"| Var["📦 변수"]
Var -->|"다른 재료로 사용"| Next["다음 요리"]
end
style Return fill:#e8f5e9,stroke:#2e7d32
print(결과): 화면에 보여주고 증발합니다. 눈으로 확인은 되지만, 변수에 담기지 않아 재사용할 수 없습니다.return 결과: 결과를 자판기 배출구로 내보냅니다. 변수에 담아서 다른 요리의 재료로 쓸 수 있습니다.
3. 왜 함수를 쓰는가?
- 재사용: 똑같은 코드를 여러 번 치기 싫어서. (Ctrl+C, Ctrl+V의 지옥에서 탈출)
- 추상화: 코드가 "어떻게(How)" 굴러가는지 몰라도, 이름만 보고 "무엇을(What)" 하는지 알기 위해서.
❌ 나쁜 예 (절차 지향)
✅ 좋은 예 (함수형)
def boil_ramen(water_ml, time_min):
# ... 복잡한 과정은 이 안에 숨김 ...
return "맛있는 라면"
# 읽는 사람은 "물 550ml, 4분 끓이면 라면이 나오는구나"만 알면 됨
my_lunch = boil_ramen(550, 4)
4. 스코프 (Scope) - 변수의 유효 범위
함수 안에서 만든 변수는 함수 안에서만 살아있습니다. 이건 불편한 게 아니라, 안전한 것입니다.
def secret_room():
money = 10000 # 지역 변수 (Local Variable)
secret_room()
# print(money) -> 🚨 에러! (NameError)
함수 밖의 전역 변수(Global Variable)를 함부로 가져다 쓰면, 나중에 코드가 꼬였을 때 범인을 찾을 수 없습니다. 함수는 되도록 자기한테 주어진 재료(Argument)만 가지고 요리해야 합니다 (Pure Function).
AI와 협업 포인트: Docstring
함수 바로 밑에 쓰는 설명(""" ... """)인 Docstring은 사람뿐만 아니라 AI에게도 중요합니다.
나중에 AI에게 "이 함수 고쳐줘"라고 할 때, AI는 이 Docstring을 읽고 "아, 이런 의도로 만든 함수군요!"라고 파악합니다.
함수 이름과 Docstring만 잘 써도 AI 코딩 성능이 200% 올라갑니다.