람다와 고차 함수(map·filter·sorted·reduce)의 완전한 이해와 언제 무엇을 쓸지 기준을 익힌다.
🎯 이 강의에서 배우는 것
람다(lambda)와 고차 함수(higher-order function)는 함수형 프로그래밍의 핵심 도구입니다. map(), filter(), sorted()를 자유자재로 사용하면 복잡한 데이터 변환을 간결하게 표현할 수 있습니다. 이 강의에서 각 함수의 동작 원리와 언제 무엇을 쓸지의 기준을 명확히 배웁니다.
🔹 람다 함수 — 익명의 일회용 함수
# lambda 문법: lambda 매개변수: 표현식 (문장 불가, 표현식만)
add = lambda x, y: x + y
print(add(3, 4)) # 7
# def와 완전히 동일 (람다 == 단일 표현식 def)
def add_def(x, y):
return x + y
# 이름 없이 즉시 사용
print((lambda x: x ** 2)(5)) # 25
# 람다가 적합한 경우: 짧고, 표현식 하나, 일회용
students = [("홍길동", 85), ("이순신", 92), ("강감찬", 78)]
students.sort(key=lambda s: s[1]) # 점수로 정렬
print(students) # [강감찬 78, 홍길동 85, 이순신 92]
# 람다가 부적합한 경우: 여러 줄 로직, 재사용 필요, 설명 필요
# 나쁜 예 — 복잡한 람다
process = lambda x: x * 2 if x > 0 else x / 2 if x < 0 else 0
# 좋은 예 — def로 의도 명확화
def process_value(x):
if x > 0: return x * 2
if x < 0: return x / 2
return 0
# Guido의 말: "람다로 할 수 있는 모든 것은 def로도 할 수 있다"
# 람다는 이름을 붙일 가치가 없을 때만 사용
🗺️ map() — 이터러블의 모든 요소 변환
nums = [1, 2, 3, 4, 5]
# map(function, iterable) → 이터레이터(lazy) 반환
doubled = map(lambda x: x * 2, nums)
print(type(doubled)) # <class 'map'> ← 이터레이터!
print(list(doubled)) # [2, 4, 6, 8, 10]
# 즉시 평가하려면 list()로 변환
print(list(map(str, [1, 2, 3]))) # ['1', '2', '3']
print(list(map(abs, [-1, -2, 3]))) # [1, 2, 3]
print(list(map(len, ["a", "bb", "ccc"]))) # [1, 2, 3]
# 여러 이터러블 동시 처리 (zip과 유사)
a = [1, 2, 3]
b = [10, 20, 30]
print(list(map(lambda x, y: x + y, a, b))) # [11, 22, 33]
# map vs 리스트 컴프리헨션 비교
# map: 내장 함수 하나를 적용할 때 간결
squares_map = list(map(lambda x: x**2, nums))
# 컴프리헨션: 표현식이 복잡하거나 조건이 있을 때 가독성 높음
squares_comp = [x**2 for x in nums]
# PEP 8 권장: 일반적으로 컴프리헨션이 더 파이썬적
# 파이썬 3에서 map은 lazy — 메모리 효율
# 100만 개 변환 중 10개만 필요한 경우
large_map = map(lambda x: x**2, range(1_000_000))
first_10 = [next(large_map) for _ in range(10)] # 10개만 계산
print(first_10) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
🔍 filter() — 조건을 만족하는 요소만 추출
nums = [-3, -1, 0, 2, 4, 6, -2]
# filter(function, iterable) → 함수가 True인 요소만
positives = list(filter(lambda x: x > 0, nums))
print(positives) # [2, 4, 6]
# filter(None, iterable) — 거짓값(0, '', None, [], False) 제거
mixed = [0, 1, "", "hello", None, [], [1,2], False, True]
truthy = list(filter(None, mixed))
print(truthy) # [1, 'hello', [1, 2], True]
# 함수 객체 전달
def is_prime(n):
if n < 2: return False
return all(n % i != 0 for i in range(2, int(n**0.5) + 1))
primes = list(filter(is_prime, range(2, 50)))
print(primes) # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
# filter vs 리스트 컴프리헨션
# filter: 함수가 이미 있을 때 간결
# 컴프리헨션: 조건을 인라인으로 쓸 때 가독성 높음
evens_filter = list(filter(lambda x: x % 2 == 0, range(20)))
evens_comp = [x for x in range(20) if x % 2 == 0]
print(evens_filter == evens_comp) # True
🔤 sorted() 완전 분석
from operator import itemgetter, attrgetter
# 기본: 오름차순
print(sorted([3, 1, 4, 1, 5, 9, 2, 6])) # [1, 1, 2, 3, 4, 5, 6, 9]
# reverse=True: 내림차순
print(sorted([3, 1, 4, 1, 5], reverse=True)) # [5, 4, 3, 1, 1]
# key 함수: 정렬 기준 지정
words = ["banana", "apple", "cherry", "date"]
print(sorted(words, key=len)) # 길이순
print(sorted(words, key=lambda w: w[-1])) # 마지막 글자순
# operator.itemgetter: 딕셔너리/튜플 정렬에 효율적
people = [
{"name": "홍길동", "age": 25},
{"name": "이순신", "age": 40},
{"name": "강감찬", "age": 30},
]
print(sorted(people, key=itemgetter("age")))
# 복합 정렬 (나이 오름차순, 이름 알파벳 역순)
print(sorted(people, key=lambda p: (p["age"], p["name"])))
# 안정 정렬(Stable Sort): 같은 키를 가진 요소는 원래 순서 유지
data = [(2, "b"), (1, "a"), (2, "a"), (1, "b")]
print(sorted(data, key=lambda x: x[0]))
# [(1, 'a'), (1, 'b'), (2, 'b'), (2, 'a')]
# 같은 숫자끼리는 원래 순서(b가 a보다 먼저였던 것 유지)
# list.sort() vs sorted()
lst = [3, 1, 4]
sorted_lst = sorted(lst) # 새 리스트 반환
lst.sort() # 원본 수정, None 반환
# sorted()는 순수 함수, list.sort()는 부수 효과
🔁 functools.reduce() — 이터러블을 단일 값으로 축약
from functools import reduce
# reduce(function, iterable[, initializer])
# function은 2개 인자를 받아 1개를 반환
# 이전 결과와 다음 요소를 누적하여 계산
nums = [1, 2, 3, 4, 5]
# 합계 (sum()으로 대체 가능 — 권장)
total = reduce(lambda acc, x: acc + x, nums)
print(total) # 15
# 곱 (내장 함수 없음 — reduce 사용 가능)
product = reduce(lambda acc, x: acc * x, nums)
print(product) # 120 (1*2*3*4*5 = 120)
# 초기값 지정
total_with_init = reduce(lambda acc, x: acc + x, nums, 100)
print(total_with_init) # 115
# 최댓값 (max()로 대체 가능)
maximum = reduce(lambda a, b: a if a > b else b, nums)
print(maximum) # 5
# 사용 기준:
# sum(), max(), min(), any(), all() → 내장 함수 사용
# 그 외 누적 계산 → reduce 사용
# 가독성이 중요하면 for 루프도 고려
# math.prod (Python 3.8+): 곱 전용 내장 함수
import math
print(math.prod(nums)) # 120
⚠️ 자주 하는 실수
- 람다에 문장(statement) 사용: 람다는 표현식(expression)만 가능합니다.
lambda x: if x > 0: return x는 SyntaxError입니다. 조건이 있으면 삼항 표현식(x if x > 0 else 0)을 사용하거나 def를 쓰세요. - map/filter 결과를 두 번 순회:
m = map(...)은 이터레이터라서 한 번 소진됩니다. 여러 번 써야 하면list()로 변환하세요. - list.sort()의 반환값 사용:
result = lst.sort()는 None을 반환합니다. 새 리스트가 필요하면sorted(lst)를 사용하세요.
📝 정리 및 다음 강의 예고
- 람다: 단일 표현식, 이름 없는 함수. 짧고 일회용일 때만 사용하세요.
map(f, it): 각 요소에 f 적용 → 이터레이터.filter(f, it): f가 True인 요소만.sorted(): 새 리스트 반환, 안정 정렬 보장. key 함수로 정렬 기준 지정.reduce(): 누적 축약. sum/max/min이 있으면 내장 함수를 먼저 확인하세요.
다음 강의: 리스트(list) 완전 해부 — 동적 배열의 내부 구조, 각 연산의 시간 복잡도, 슬라이싱의 완전한 이해를 배웁니다.
관련 주제
- lambda 익명함수
- map()·filter()
- sorted() key 함수
- operator.itemgetter
- functools.reduce
- 복합 정렬 기준
- 개발·프로그래밍
- 개발·프로그래밍 강의
- 파이썬 기초 40강 — 처음 배우는 프로그래밍
- 무료강의
- 무료 온라인 강의
- NUGUNA
- 누구나
📚 시리즈 전체 공유
파이썬 기초 40강 — 처음 배우는 프로그래밍
이 강의가 속한 시리즈는 총 32강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.
댓글
0/1000
불러오는 중...
