# 여기에 코드를 작성하세요
Exercises: Chapter 9
Chapter 9: Functions - 연습문제
함수 정의, 매개변수, 지역/전역 변수, 람다, 제너레이터, 데코레이터
문제 1: 기본 함수와 Docstring
다음 요구사항에 맞는 함수를 작성하세요:
- 이름:
calculate_bmi - 매개변수:
weight(kg),height(m) - 반환값: BMI 수치 (체중 / 신장²)
- Docstring 작성 (함수 설명, 매개변수, 반환값 포함)
- BMI 범주 판정 추가:
- 18.5 미만: “저체중”
- 18.5~23 미만: “정상”
- 23~25 미만: “과체중”
- 25 이상: “비만”
함수를 호출하고 __doc__ 속성으로 docstring을 출력하세요.
출력 예시:
BMI: 24.22
범주: 과체중
문제 2: 기본값과 키워드 인자
온라인 쇼핑몰의 가격 계산 함수를 작성하세요:
def calculate_price(price, quantity=1, discount=0, tax_rate=0.1):
# 구현계산 방식:
- 기본 금액 = price × quantity
- 할인 적용 = 기본 금액 × (1 - discount)
- 세금 포함 = 할인 적용 금액 × (1 + tax_rate)
테스트:
calculate_price(10000) # 11000.0
calculate_price(10000, quantity=3) # 33000.0
calculate_price(10000, quantity=2, discount=0.2) # 17600.0
calculate_price(10000, discount=0.1, tax_rate=0) # 9000.0# 여기에 코드를 작성하세요
문제 3: 가변 위치 인자 (*args)
여러 개의 숫자를 받아 통계 정보를 반환하는 함수를 작성하세요:
def number_stats(*numbers):
# 구현반환값: 딕셔너리
count: 숫자 개수sum: 합계mean: 평균min: 최솟값max: 최댓값
주의: 인자가 없을 때는 적절한 메시지와 함께 None 반환
테스트:
number_stats(1, 2, 3, 4, 5)
# {'count': 5, 'sum': 15, 'mean': 3.0, 'min': 1, 'max': 5}
number_stats(10, 20)
# {'count': 2, 'sum': 30, 'mean': 15.0, 'min': 10, 'max': 20}# 여기에 코드를 작성하세요
문제 4: 가변 키워드 인자 (**kwargs)
학생 정보를 받아 프로필 문자열을 생성하는 함수를 작성하세요:
def create_student_profile(name, student_id, **additional_info):
# 구현요구사항:
name과student_id는 필수- 추가 정보는 키워드 인자로 자유롭게 받기
- 모든 정보를 보기 좋게 정리하여 문자열로 반환
테스트:
print(create_student_profile(
"김철수",
"2023001",
major="컴퓨터공학",
grade=3,
gpa=3.8,
club="코딩동아리"
))출력 예시:
=== 학생 프로필 ===
이름: 김철수
학번: 2023001
전공: 컴퓨터공학
학년: 3
학점: 3.8
동아리: 코딩동아리
# 여기에 코드를 작성하세요
문제 5: Mutable 객체와 부작용
다음 두 가지 버전의 리스트 처리 함수를 작성하고 차이를 설명하세요:
버전 1: 원본 수정 (in-place)
def remove_negatives_inplace(numbers):
"""원본 리스트에서 음수 제거"""
# 구현버전 2: 새 리스트 반환
def remove_negatives_copy(numbers):
"""새 리스트를 만들어 반환 (원본 유지)"""
# 구현테스트 코드:
# 버전 1 테스트
list1 = [1, -2, 3, -4, 5, -6]
remove_negatives_inplace(list1)
print("버전 1 - 원본:", list1) # [1, 3, 5]
# 버전 2 테스트
list2 = [1, -2, 3, -4, 5, -6]
new_list = remove_negatives_copy(list2)
print("버전 2 - 원본:", list2) # [1, -2, 3, -4, 5, -6]
print("버전 2 - 새 리스트:", new_list) # [1, 3, 5]질문: 어떤 상황에서 각 버전을 사용하는 것이 좋을까요?
# 여기에 코드를 작성하세요
문제 6: Local vs Global 변수
다음 코드의 출력을 예측하고, 실제로 실행하여 확인하세요. 그리고 각 경우를 설명하세요.
counter = 0
def test1():
counter = 10
print("test1 내부:", counter)
def test2():
global counter
counter = 20
print("test2 내부:", counter)
def test3():
print("test3 내부:", counter)
print("초기:", counter)
test1()
print("test1 후:", counter)
test2()
print("test2 후:", counter)
test3()추가 문제: 은행 계좌 클래스를 구현하되, 전체 계좌의 총 잔액을 추적하는 전역 변수를 사용하세요.
# 여기에 코드를 작성하세요
문제 7: 함수를 변수에 할당
여러 변환 함수를 딕셔너리에 저장하고 활용하는 시스템을 만드세요:
요구사항:
- 온도 변환 함수들 작성:
celsius_to_fahrenheit: 섭씨 → 화씨fahrenheit_to_celsius: 화씨 → 섭씨celsius_to_kelvin: 섭씨 → 켈빈kelvin_to_celsius: 켈빈 → 섭씨
- 함수를 딕셔너리에 저장:
converters = {
'c_to_f': celsius_to_fahrenheit,
# ...
}- 사용자 입력을 받아 해당 변환 실행
테스트:
convert_temperature(100, 'c_to_f') # 212.0
convert_temperature(32, 'f_to_c') # 0.0
convert_temperature(0, 'c_to_k') # 273.15# 여기에 코드를 작성하세요
문제 8: Lambda 표현식 활용
다음 데이터를 lambda 표현식을 사용하여 다양하게 정렬하세요:
products = [
{'name': 'Laptop', 'price': 1200, 'rating': 4.5, 'stock': 15},
{'name': 'Mouse', 'price': 25, 'rating': 4.8, 'stock': 50},
{'name': 'Keyboard', 'price': 75, 'rating': 4.3, 'stock': 30},
{'name': 'Monitor', 'price': 300, 'rating': 4.7, 'stock': 20},
]작업:
- 가격 기준 오름차순 정렬
- 평점 기준 내림차순 정렬
- 재고가 30 이상인 제품만 필터링 (filter 사용)
- 모든 가격을 10% 인상 (map 사용)
- 가격/평점 비율로 정렬 (가성비 순)
힌트: sorted(), filter(), map() 함수와 lambda를 조합하세요.
# 여기에 코드를 작성하세요
products = [
{'name': 'Laptop', 'price': 1200, 'rating': 4.5, 'stock': 15},
{'name': 'Mouse', 'price': 25, 'rating': 4.8, 'stock': 50},
{'name': 'Keyboard', 'price': 75, 'rating': 4.3, 'stock': 30},
{'name': 'Monitor', 'price': 300, 'rating': 4.7, 'stock': 20},
]
문제 9: Generator 함수 기초
다음 generator 함수들을 작성하세요:
1. 피보나치 수열 생성기
def fibonacci(n):
"""처음 n개의 피보나치 수를 생성"""
# yield 사용하여 구현2. 파일 줄 단위 읽기
def read_lines(filename):
"""파일을 한 줄씩 읽어 yield"""
# 빈 줄과 주석(#으로 시작)은 건너뛰기3. 무한 카운터
def infinite_counter(start=0, step=1):
"""무한히 증가하는 카운터"""
# 구현테스트:
# 피보나치
for num in fibonacci(10):
print(num, end=' ') # 0 1 1 2 3 5 8 13 21 34
# 무한 카운터 (처음 5개만)
counter = infinite_counter(10, 2)
for _ in range(5):
print(next(counter)) # 10 12 14 16 18# 여기에 코드를 작성하세요
문제 10: Generator를 사용한 데이터 파이프라인
대용량 로그 파일을 처리하는 generator 파이프라인을 구현하세요:
# 샘플 로그 데이터
log_lines = [
"2024-01-01 10:00:00 INFO User login: user123",
"2024-01-01 10:05:00 ERROR Database connection failed",
"2024-01-01 10:10:00 INFO User logout: user123",
"2024-01-01 10:15:00 WARNING High memory usage: 85%",
"2024-01-01 10:20:00 ERROR File not found: data.txt",
]구현할 generator 함수들:
generate_logs(lines): 로그 라인을 하나씩 yieldparse_log(logs): 각 로그를 딕셔너리로 파싱{'timestamp': ..., 'level': ..., 'message': ...}
filter_by_level(logs, level): 특정 레벨만 필터링format_log(logs): 로그를 보기 좋게 포맷
사용 예시:
# Generator 체인
logs = generate_logs(log_lines)
parsed = parse_log(logs)
errors = filter_by_level(parsed, 'ERROR')
formatted = format_log(errors)
for log in formatted:
print(log)힌트: Generator는 필요할 때만 데이터를 처리하므로 메모리 효율적입니다.
# 여기에 코드를 작성하세요
log_lines = [
"2024-01-01 10:00:00 INFO User login: user123",
"2024-01-01 10:05:00 ERROR Database connection failed",
"2024-01-01 10:10:00 INFO User logout: user123",
"2024-01-01 10:15:00 WARNING High memory usage: 85%",
"2024-01-01 10:20:00 ERROR File not found: data.txt",
]
문제 11**: 다목적 Decorator 만들기
함수의 실행 시간을 측정하고 결과를 캐싱하는 decorator를 작성하세요.
요구사항:
@timer: 함수 실행 시간 측정@memoize: 함수 결과 캐싱 (같은 인자로 호출 시 저장된 결과 반환)- 두 decorator를 함께 사용 가능해야 함
기본 구조:
import time
def timer(func):
"""함수 실행 시간을 측정하는 decorator"""
def wrapper(*args, **kwargs):
start_time = time.time()
# 여기에 구현
result = func(*args, **kwargs)
# 여기에 구현 (실행 시간 출력)
return result
return wrapper
def memoize(func):
"""함수 결과를 캐싱하는 decorator"""
cache = {} # 결과 저장용 딕셔너리
def wrapper(*args):
# 여기에 구현
# 힌트: args가 cache에 있으면 저장된 값 반환
# 없으면 함수 실행 후 결과를 cache에 저장
pass
return wrapper
# 테스트용 함수
@timer
@memoize
def fibonacci(n):
"""재귀적 피보나치 (느린 버전)"""
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 테스트
print(fibonacci(10)) # 첫 실행 - 느림
print(fibonacci(10)) # 두 번째 실행 - 캐시에서 즉시 반환
print(fibonacci(15)) # 다른 값추가 도전: - 캐시 크기 제한 추가 - 캐시 통계 (히트/미스) 출력 - 특정 시간 후 캐시 만료
import time
def timer(func):
"""함수 실행 시간을 측정하는 decorator"""
def wrapper(*args, **kwargs):
start_time = time.time()
# 여기에 구현
result = func(*args, **kwargs)
# 여기에 구현 (실행 시간 출력)
return result
return wrapper
def memoize(func):
"""함수 결과를 캐싱하는 decorator"""
cache = {} # 결과 저장용 딕셔너리
def wrapper(*args):
# 여기에 구현
# 힌트: args가 cache에 있으면 저장된 값 반환
# 없으면 함수 실행 후 결과를 cache에 저장
pass
return wrapper
# 여기에 추가 코드 작성