5주차 · 함수와 출력
이 장의 핵심은 한 문장입니다.
함수는 “작은 기계”를 만드는 것이고, 출력은 그 결과를 보여주는 것이다.
지금까지 우리는 코드를 위에서 아래로 쭉 썼습니다. 하지만 코드가 길어지면 어디가 어떤 일을 하는지 찾기 어렵고, 같은 계산을 여러 번 반복해서 쓰게 됩니다. 함수를 사용하면 이 문제를 해결할 수 있습니다.
def, 호출,return의 기본 문법을 쓸 수 있습니다.- 매개변수와 반환값이 무엇인지 구분할 수 있습니다.
print()와return의 차이를 설명할 수 있습니다.f"..."포맷 문자열로 깔끔한 출력을 만들 수 있습니다.- 간단한 텍스트 파일에 결과를 저장할 수 있습니다.
0) 함수는 왜 필요한가? — 동기 부여
Section titled “0) 함수는 왜 필요한가? — 동기 부여”함수 없이 같은 계산을 3번 반복하면
Section titled “함수 없이 같은 계산을 3번 반복하면”# 섭씨 → 화씨 변환을 3번 해야 하는 상황c1 = 20f1 = c1 * 9 / 5 + 32print(f1)
c2 = 35f2 = c2 * 9 / 5 + 32print(f2)
c3 = -5f3 = c3 * 9 / 5 + 32print(f3)문제점:
- 같은 공식
* 9 / 5 + 32가 3번 반복됩니다. - 만약 공식을 수정해야 하면 3군데를 모두 고쳐야 합니다.
- 10개, 100개라면? 실수 확률이 급격히 높아집니다.
함수를 만들면
Section titled “함수를 만들면”def c_to_f(c): return c * 9 / 5 + 32
print(c_to_f(20)) # 68.0print(c_to_f(35)) # 95.0print(c_to_f(-5)) # 23.0- 공식은 한 곳에만 있습니다.
- 수정이 필요하면 함수 안만 고치면 됩니다.
- 코드가 짧고, 의도가 명확합니다.
1) 함수의 기본 구조
Section titled “1) 함수의 기본 구조”flowchart TB A["1) 함수 정의<br/>def add(a, b):"] --> B["2) 호출<br/>result = add(3, 5)"] B --> C["3) 인자 전달<br/>a=3, b=5"] C --> D["4) 본문 실행<br/>return a + b"] D --> E["5) 반환값 전달<br/>result = 8"] E --> F["6) 호출 지점으로 복귀<br/>다음 줄 실행"]
함수 문법 뼈대
Section titled “함수 문법 뼈대”def 함수이름(매개변수1, 매개변수2): # 함수 본문 (들여쓰기 4칸) result = 매개변수1 + 매개변수2 return result # 결과를 돌려줌
# 함수 호출answer = 함수이름(10, 20)print(answer) # 30| 용어 | 의미 | 예시 |
|---|---|---|
| 정의(definition) | 함수를 만드는 것 | def add(a, b): |
| 호출(call) | 함수를 사용하는 것 | add(3, 5) |
| 매개변수(parameter) | 함수가 받는 입력 이름 | a, b |
| 인자(argument) | 호출할 때 넘기는 실제 값 | 3, 5 |
| 반환값(return value) | 함수가 돌려주는 결과 | 8 |
2) 함수 호출 과정을 한 줄씩 추적하기
Section titled “2) 함수 호출 과정을 한 줄씩 추적하기”함수가 호출되면 어떤 순서로 실행되는지, 구체적으로 따라가 봅시다.
def multiply(x, y): result = x * y return result
a = 4b = 7answer = multiply(a, b)print(answer)| 순서 | 실행되는 코드 | 설명 |
|---|---|---|
| 1 | def multiply(x, y): | 함수 등록 (아직 실행 안 함) |
| 2 | a = 4 | 변수 a에 4 저장 |
| 3 | b = 7 | 변수 b에 7 저장 |
| 4 | multiply(a, b) 호출 | a의 값 4가 x로, b의 값 7이 y로 전달 |
| 5 | result = x * y | 4 * 7 = 28, result에 저장 |
| 6 | return result | 28을 호출한 곳으로 돌려줌 |
| 7 | answer = 28 | 반환값 28이 answer에 저장 |
| 8 | print(answer) | 28 출력 |
핵심: 함수가 호출되면 “함수 안으로 들어갔다가 → return을 만나면 → 호출한 곳으로 돌아온다.”
3) return과 print()는 다릅니다
Section titled “3) return과 print()는 다릅니다”이것은 초보자가 가장 많이 혼동하는 부분입니다.
# print()만 쓴 함수def show_double(x): print(x * 2) # 화면에 출력만 함
# return을 쓴 함수def get_double(x): return x * 2 # 값을 돌려줌# 차이 확인a = show_double(5) # 화면에 10 출력print("a의 값:", a) # a의 값: None ← 반환값이 없다!
b = get_double(5) # 화면에 아무것도 안 나옴print("b의 값:", b) # b의 값: 10 ← 값을 받았다!print() | return | |
|---|---|---|
| 역할 | 화면에 보여주기 | 값을 돌려주기 |
| 결과 저장 | 불가능 (항상 None) | 변수에 저장 가능 |
| 다른 계산에 활용 | 불가능 | 가능 (get_double(5) + 10) |
| 언제 쓰나 | 디버그 확인, 최종 출력 | 계산 결과를 넘겨야 할 때 |
4) 매개변수 활용
Section titled “4) 매개변수 활용”매개변수가 없는 함수
Section titled “매개변수가 없는 함수”def greet(): return "안녕하세요!"
message = greet()print(message)매개변수가 여러 개인 함수
Section titled “매개변수가 여러 개인 함수”def bmi(weight_kg, height_m): return weight_kg / (height_m ** 2)
my_bmi = bmi(70, 1.75)print(f"BMI: {my_bmi:.1f}") # BMI: 22.9기본값이 있는 매개변수
Section titled “기본값이 있는 매개변수”매개변수에 기본값을 지정하면, 호출 시 생략할 수 있습니다.
def power(base, exp=2): # exp의 기본값은 2 return base ** exp
print(power(3)) # 3^2 = 9 (exp 생략 → 기본값 2 사용)print(power(3, 3)) # 3^3 = 27 (exp=3으로 지정)print(power(2, 10)) # 2^10 = 10245) 함수 안에서 조건문과 반복문 사용하기
Section titled “5) 함수 안에서 조건문과 반복문 사용하기”함수 안에서 if문이나 for문을 자유롭게 쓸 수 있습니다.
함수 + 조건문
Section titled “함수 + 조건문”def classify_voltage(v): if v < 3.0: return "LOW" elif v < 4.0: return "NORMAL" else: return "HIGH"
print(classify_voltage(2.5)) # LOWprint(classify_voltage(3.7)) # NORMALprint(classify_voltage(4.5)) # HIGH함수 + 반복문
Section titled “함수 + 반복문”def sum_range(start, end): total = 0 for i in range(start, end + 1): total += i return total
print(sum_range(1, 10)) # 55print(sum_range(1, 100)) # 5050함수 + 반복문 + 조건문
Section titled “함수 + 반복문 + 조건문”def count_multiples(n, divisor): """1부터 n까지 중 divisor의 배수 개수를 세는 함수""" count = 0 for i in range(1, n + 1): if i % divisor == 0: count += 1 return count
print(count_multiples(20, 3)) # 6 (3,6,9,12,15,18)print(count_multiples(100, 7)) # 146) 변수의 범위(scope): 왜 변수가 “사라지는가”
Section titled “6) 변수의 범위(scope): 왜 변수가 “사라지는가””함수 안에서 만든 변수는 함수 밖에서 쓸 수 없습니다. 이것을 지역 변수(local variable) 라고 합니다.
def demo(): y = 20 # 지역 변수: demo() 안에서만 존재 return y
result = demo()print(result) # 20 (return으로 꺼낸 값)# print(y) # NameError! y는 함수 밖에서 접근 불가| 변수 종류 | 어디서 만들었나 | 어디서 쓸 수 있나 |
|---|---|---|
| 지역 변수 | 함수 안 | 함수 안에서만 |
| 전역 변수 | 함수 밖 (스크립트 최상위) | 어디서든 읽기 가능 |
x = 10 # 전역 변수
def add_to_x(n): return x + n # 전역 변수 x를 읽는 것은 가능
print(add_to_x(5)) # 157) f-string 완전 가이드
Section titled “7) f-string 완전 가이드”f"..." (formatted string literal)은 문자열 안에 변수 값을 넣는 가장 편리한 방법입니다.
기본 사용법
Section titled “기본 사용법”name = "센서A"value = 3.14159
print(f"장치: {name}") # 장치: 센서Aprint(f"측정값: {value}") # 측정값: 3.14159print(f"계산: {value * 2}") # 계산: 6.28318 (수식도 가능)f"..." 안의 { } 중괄호에 변수 이름이나 수식을 넣으면, 그 값이 문자열에 자동으로 들어갑니다.
숫자 포맷 지정
Section titled “숫자 포맷 지정”| 포맷 | 의미 | 예시 코드 | 결과 |
|---|---|---|---|
:.2f | 소수점 아래 2자리 | f"{3.14159:.2f}" | 3.14 |
:.4f | 소수점 아래 4자리 | f"{3.14159:.4f}" | 3.1416 |
:d | 정수 | f"{42:d}" | 42 |
:05d | 정수, 5자리, 빈 칸은 0으로 채움 | f"{42:05d}" | 00042 |
:>10 | 오른쪽 정렬, 전체 10칸 | f"{'hello':>10}" | hello |
:<10 | 왼쪽 정렬, 전체 10칸 | f"{'hello':<10}" | hello |
실용 예제: 표 형태 출력
Section titled “실용 예제: 표 형태 출력”for i in range(1, 6): squared = i ** 2 cubed = i ** 3 print(f"i={i:2d} 제곱={squared:4d} 세제곱={cubed:5d}")출력:
i= 1 제곱= 1 세제곱= 1i= 2 제곱= 4 세제곱= 8i= 3 제곱= 9 세제곱= 27i= 4 제곱= 16 세제곱= 64i= 5 제곱= 25 세제곱= 125자릿수를 맞추면 결과가 표처럼 깔끔하게 정렬됩니다.
print()의 유용한 옵션
Section titled “print()의 유용한 옵션”# sep: 값 사이 구분자 (기본값: 공백)print("A", "B", "C", sep=", ") # A, B, Cprint("2025", "03", "26", sep="-") # 2025-03-26
# end: 줄 끝 문자 (기본값: 줄바꿈 \n)for i in range(5): print(i, end=" ") # 0 1 2 3 4 (한 줄에)print() # 줄바꿈8) 함수 설계 원칙
Section titled “8) 함수 설계 원칙”규칙 1: 한 함수에는 한 가지 일만
Section titled “규칙 1: 한 함수에는 한 가지 일만”# 나쁜 예: 계산 + 출력 + 저장을 한 함수에서def do_everything(c): f = c * 9 / 5 + 32 print(f"결과: {f}") with open("result.txt", "w") as file: file.write(str(f))
# 좋은 예: 역할별로 분리def c_to_f(c): return c * 9 / 5 + 32
def save_to_file(text, path): with open(path, "w", encoding="utf-8") as file: file.write(text)규칙 2: 함수 이름은 동사로 시작
Section titled “규칙 2: 함수 이름은 동사로 시작”| 좋은 이름 | 나쁜 이름 | 이유 |
|---|---|---|
calculate_bmi() | bmi_thing() | 무엇을 하는지 명확 |
classify_voltage() | voltage() | 동작(분류)이 드러남 |
sum_range() | my_function() | 의미 전달 |
규칙 3: 결과는 return으로, 확인은 print()로
Section titled “규칙 3: 결과는 return으로, 확인은 print()로”def compute_average(total, n): return total / n
avg = compute_average(270, 5)print(f"평균: {avg:.1f}") # 함수 바깥에서 출력9) 간단한 파일 저장
Section titled “9) 간단한 파일 저장”계산 결과를 텍스트 파일로 저장하는 기본 패턴입니다.
with open(...) 기본 문법
Section titled “with open(...) 기본 문법”with open("output/result.txt", "w", encoding="utf-8") as f: f.write("첫 번째 줄\n") f.write("두 번째 줄\n")| 요소 | 의미 |
|---|---|
"output/result.txt" | 저장할 파일 경로 |
"w" | 쓰기 모드 (write). 기존 내용 덮어씀 |
"a" | 추가 모드 (append). 기존 내용 뒤에 이어 씀 |
"r" | 읽기 모드 (read) |
encoding="utf-8" | 한글이 깨지지 않도록 인코딩 지정 |
as f | 파일 객체에 f라는 이름을 붙임 |
f.write(...) | 문자열을 파일에 씀 |
with open("output/result.txt", "r", encoding="utf-8") as f: content = f.read()print(content)FILE *fp = fopen("report.txt", "w");if (fp != NULL) { fprintf(fp, "value=%d\n", 10); fclose(fp);}with open("report.txt", "w", encoding="utf-8") as f: f.write(f"value={10}\n")# with 블록이 끝나면 자동 close10) 디버깅 습관
Section titled “10) 디버깅 습관”- 함수마다 입력/출력 1회 확인: 호출 직후
print(f"result={result}")로 반환값 확인 return빠뜨리면None: 결과가None이면return을 확인- 매개변수 이름 확인: 호출할 때 순서를 바꾸면 결과가 달라짐
- 작은 값으로 먼저 테스트: 큰 범위를 넣기 전에
sum_range(1, 3)정도로 확인 - 한 함수에 한 책임: 함수가 너무 길면 분리 신호
초보자 실수와 교정 패턴
Section titled “초보자 실수와 교정 패턴”| 실수 | 증상 | 수정 방법 |
|---|---|---|
return 누락 | 호출 결과가 None | 계산 끝에 return value 추가 |
| 지역 변수 외부 사용 | NameError | 함수에서 return 후 변수에 저장 |
def 뒤에 : 누락 | SyntaxError | def 함수이름(...): 확인 |
| 함수 정의 전에 호출 | NameError | 정의를 호출보다 위에 배치 |
print()와 return 혼동 | 값 재사용 불가 | 계산 함수엔 return, 출력은 밖에서 |
f-string에서 f 빼먹음 | {변수}가 그대로 출력 | 따옴표 앞에 f 붙이기 |
예제 1 — 함수 정의와 호출 기초
Section titled “예제 1 — 함수 정의와 호출 기초” 예제 1 해설
Section titled “예제 1 해설”def c_to_f(c):— 매개변수c를 받는 함수 정의return c * 9 / 5 + 32— 계산 결과를 돌려줌temp_f = c_to_f(25)— 함수 호출, 반환값을temp_f에 저장for c in range(0, 41, 10):— 0, 10, 20, 30, 40으로 반복 호출f"{c:3d}"— 정수를 3자리로 정렬 출력f"{f:6.1f}"— 실수를 전체 6자리, 소수점 1자리로 정렬
예제 2 — return vs print 차이 확인
Section titled “예제 2 — return vs print 차이 확인” 예제 2 해설
Section titled “예제 2 해설”show_square(5)는 화면에결과: 25를 보여주지만, 반환값은Noneget_square(5)는 화면에 아무것도 안 보이지만, 값25를 돌려줌- 핵심: 다른 곳에서 써야 할 값은 반드시
return으로 돌려줘야 합니다
예제 3 — 함수 + 조건문 결합
Section titled “예제 3 — 함수 + 조건문 결합” 예제 3 해설
Section titled “예제 3 해설”- 함수가 조건에 따라 다른 값을
return합니다 range(25, 50, 5)로 25, 30, 35, 40, 45를 만들고,/10으로 2.5 ~ 4.5 생성- 함수를 호출한 결과를
label변수에 저장 후 출력
예제 4 — 함수 + 반복문 결합
Section titled “예제 4 — 함수 + 반복문 결합” 예제 4 해설
Section titled “예제 4 해설”- 함수 안에서
for+if조합으로 조건에 맞는 값만 누적 return total, count— 두 값을 동시에 반환 (쉼표로 구분)s, c = sum_multiples(50, 7)— 반환된 두 값을 각각 변수에 저장
예제 5 — f-string 포매팅 실전
Section titled “예제 5 — f-string 포매팅 실전” 예제 5 해설
Section titled “예제 5 해설”:.2f— 소수점 아래 2자리로 표시:02d— 정수를 2자리로, 빈 자리는 0으로 채움:<8/:>6— 왼쪽/오른쪽 정렬로 깔끔한 표 출력- 함수
grade()와 결합해서 계산 + 포매팅 분리
예제 6 — 간단한 파일 저장
Section titled “예제 6 — 간단한 파일 저장” 예제 6 해설
Section titled “예제 6 해설”- 계산 함수
c_to_f(),classify()정의 — 각각 한 가지 역할만 - 함수 호출 후 결과를 변수에 저장
with open(..., "w")— 쓰기 모드로 파일 열기f.write(f"...")— f-string으로 포맷된 문자열을 파일에 저장with open(..., "r")— 다시 읽어서 내용 확인 (read-back 패턴)
실습 문제 · 직접 코딩
Section titled “실습 문제 · 직접 코딩”문제: BMI를 계산하는 함수와 결과를 분류하는 함수를 작성하세요.
문제: f-string을 사용해서 구구단 표를 깔끔하게 출력하세요.
문제: 1부터 N까지 중에서 소수(prime)를 찾는 함수를 작성하세요.
문제: 기본값 매개변수를 활용한 전력 계산 함수를 만드세요.
문제: 4개의 작은 함수를 조합해서 온도 변환 → 상태 분류 → 반복 리포트 출력을 만드세요.