파이썬 심화: 람다식과 고차 함수
반갑습니다. 저는 여러분의 코딩 길잡이, 재준봇입니다.
자, 여러분. 지금까지 파이썬의 기초를 아주 성실하게 달려오셨습니다. 그런데 공부를 하다 보면 이런 생각이 들 때가 있을 거예요. “아니, 굳이 함수를 이렇게 길게 만들어야 해? 그냥 한 줄로 쓱 끝낼 순 없을까?” 하는 생각 말이죠.
오늘 우리가 배울 내용은 바로 그 가려운 곳을 싹 긁어줄 파이썬의 마법, 람다식과 고차 함수입니다. 이름만 들으면 무슨 수학 논문 같고 어려워 보이지만, 사실 알고 보면 “귀차니즘”의 결정체라고 할 수 있습니다. 코드를 짧게 줄이고 싶어 하는 개발자들의 욕망이 만들어낸 아주 효율적인 도구죠.
오늘 이 강의만 완벽하게 소화하신다면, 여러분은 이제 단순한 코더가 아니라 파이썬의 고급 문법을 다루는 ‘멋쟁이 개발자’의 길로 들어서게 될 겁니다. 준비되셨나요? 그럼 바로 시작하겠습니다.
12강: 파이썬 심화 - 람다식과 고차 함수
1. 람다(Lambda)란 무엇인가? 이름 없는 함수들의 반란
먼저 람다식을 이해하기 위해 아주 찰떡같은 비유를 들어볼게요.
우리가 보통 함수를 만들 때 def를 사용하죠? 이건 마치 정식으로 집을 짓는 것과 같습니다. 설계도를 그리고, 주소를 정하고, 기둥을 세우고, 대문을 다는 과정이죠. 나중에 언제든 다시 찾아올 수 있도록 이름(함수명)을 붙여서 저장해두는 것입니다.
그런데 세상에는 집까지 지을 필요 없이, 잠깐 텐트만 치고 쉬었다가 바로 걷어버려도 되는 상황이 많습니다. 딱 한 번 쓰고 버릴 함수, 혹은 굳이 이름을 붙여서 메모리를 차지하게 하고 싶지 않은 아주 간단한 계산식 말이죠. 이때 사용하는 것이 바로 람다식입니다. 람다는 한마디로 일회용 텐트 같은 함수입니다.
람다식의 문법 구조
lambda 매개변수 : 표현식
여기서 중요한 건 람다식은 return이라는 글자를 쓰지 않아도 결과값을 자동으로 반환한다는 점입니다. 진짜 신기하죠?
[코드 예제 1] 함수 구현의 3가지 단계: 정식 함수에서 람다까지
똑같은 더하기 기능을 구현하는 세 가지 방법을 보여드리겠습니다. 어떻게 진화하는지 눈여겨보세요.
# 방법 1: 가장 정석적인 정식 함수 (def 사용)
# 이름을 붙여서 정의하고, 나중에 계속 불러다 쓰는 방식입니다.
def add_traditional(a, b):
return a + b
# 방법 2: 변수에 할당한 람다 함수
# 람다식을 변수에 담아서 함수처럼 사용하는 방식입니다.
add_lambda_var = lambda a, b: a + b
# 방법 3: 이름 없이 즉석에서 호출하는 람다 함수
# 변수조차 만들지 않고 필요한 순간에 바로 실행해 버리는 방식입니다.
result = (lambda a, b: a + b)(10, 20)
print(f"정식 함수 결과: {add_traditional(10, 20)}")
print(f"변수 할당 람다 결과: {add_lambda_var(10, 20)}")
print(f"즉석 실행 람다 결과: {result}")
코드 뜯어보기
- 방법 1에서는
def키워드로 이름을 정하고return을 통해 값을 돌려줍니다. 가장 표준적이지만 코드가 길죠. - 방법 2에서는
lambda a, b: a + b라고 썼습니다. “a와 b를 받아서 a + b를 해라”라는 뜻입니다. 이걸add_lambda_var라는 이름표에 붙여준 겁니다. - 방법 3이 람다의 정수입니다.
(lambda a, b: a + b)라고 함수를 정의하자마자 뒤에(10, 20)을 붙여 바로 실행했습니다. 이름조차 필요 없는 일회용 함수인 셈이죠.
2. 고차 함수: 함수를 부리는 함수
람다를 배웠다면 이제 이 람다를 어디에 써먹을지를 알아야 합니다. 여기서 등장하는 개념이 바로 고차 함수(Higher-Order Function)입니다.
고차 함수란 무엇일까요? 아주 간단합니다.
- 함수를 인자로 받거나,
- 함수를 결과로 반환하는 함수를 말합니다.
비유를 들어볼까요? 일반 함수가 ‘직원’이라면, 고차 함수는 ‘매니저’입니다. 매니저는 직접 일을 하기보다, 어떤 직원(함수)을 데려와서 “자, 네가 이 데이터를 처리해!”라고 지시하는 역할을 합니다.
파이썬에서 가장 대표적인 고차 함수 3대장이 바로 map, filter, reduce입니다. 이거 모르면 파이썬 심화 단계로 넘어갈 수 없으니 집중하세요!
(1) map(): 모든 요소에 마법을 부려라
map은 리스트의 모든 요소에 동일한 함수를 적용해서 새로운 리스트를 만드는 함수입니다.
상황: 숫자 리스트가 있는데, 모든 숫자를 제곱하고 싶을 때!
[코드 예제 2] map()을 활용한 데이터 변환 3가지 방법
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# 방법 1: 전통적인 for 반복문 사용
# 가장 직관적이지만 코드가 길고 지루합니다.
squared_for = []
for n in numbers:
squared_for.append(n * n)
# 방법 2: map()과 정식 함수 조합
def square(n):
return n * n
squared_map_def = list(map(square, numbers))
# 방법 3: map()과 람다식 조합 (실무 최강 조합)
# 함수를 따로 만들 필요 없이 한 줄로 끝냅니다.
squared_map_lambda = list(map(lambda x: x * x, numbers))
print(f"for문 결과: {squared_for}")
print(f"map + def 결과: {squared_map_def}")
print(f"map + lambda 결과: {squared_map_lambda}")
코드 뜯어보기
- 방법 1은 빈 리스트를 만들고 하나씩 집어넣는 노가다 방식입니다.
- 방법 2는
square라는 정식 함수를 만들어서map에게 전달했습니다.map은 “아, 이 함수를 리스트 모든 애들한테 적용하면 되는구나!”라고 이해합니다. - 방법 3이 핵심입니다. 람다를 이용해
lambda x: x * x라는 일회용 함수를 즉석에서 만들어map에게 줬습니다. 코드가 획기적으로 줄어들었죠?
(2) filter(): 원하는 녀석만 걸러내라
filter는 이름 그대로 필터링입니다. 조건 함수를 넣어서, 그 조건이 ‘참(True)’인 요소만 남기는 함수입니다.
상황: 숫자 리스트에서 짝수만 골라내고 싶을 때!
[코드 예제 3] filter()를 활용한 데이터 추출 3가지 방법
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 방법 1: 전통적인 for문과 if문 조합
evens_for = []
for n in numbers:
if n % 2 == 0:
evens_for.append(n)
# 방법 2: filter()와 정식 함수 조합
def is_even(n):
return n % 2 == 0
evens_filter_def = list(filter(is_even, numbers))
# 방법 3: filter()와 람다식 조합
evens_filter_lambda = list(filter(lambda x: x % 2 == 0, numbers))
print(f"for + if 결과: {evens_for}")
print(f"filter + def 결과: {evens_filter_def}")
print(f"filter + lambda 결과: {evens_filter_lambda}")
코드 뜯어보기
- 방법 1은
if문을 통해 하나하나 검사하는 정석적인 방법입니다. - 방법 2는
is_even이라는 판별 함수를 만들어filter에게 줬습니다.filter는 이 함수가True를 뱉는 값만 수집합니다. - 방법 3은 람다를 통해 “x를 2로 나눈 나머지가 0인 것만 가져와!”라고 한 줄로 지시한 것입니다.
(3) reduce(): 하나로 뭉쳐라
reduce는 조금 특별합니다. map과 filter는 결과가 리스트 형태지만, reduce는 모든 요소를 누적 계산해서 ‘단 하나의 값’으로 만들어버립니다. (주의: functools 모듈에서 가져와야 합니다.)
상황: 리스트에 있는 모든 숫자를 다 곱해서 총합을 구하고 싶을 때!
[코드 예제 4] reduce()를 활용한 값 누적 3가지 방법
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# 방법 1: for문을 이용한 누적 합계
total_for = 1
for n in numbers:
total_for *= n
# 방법 2: reduce()와 정식 함수 조합
def multiply(a, b):
return a * b
total_reduce_def = reduce(multiply, numbers)
# 방법 3: reduce()와 람다식 조합
total_reduce_lambda = reduce(lambda x, y: x * y, numbers)
print(f"for문 누적 결과: {total_for}")
print(f"reduce + def 결과: {total_reduce_def}")
print(f"reduce + lambda 결과: {total_reduce_lambda}")
코드 뜯어보기
- 방법 1은 변수 하나를 만들어 놓고 계속 곱해나가는 방식입니다.
- 방법 2는
multiply함수를 통해 두 수를 곱하는 규칙을 정해주고, 이를reduce가 리스트 끝까지 반복 수행하게 합니다. - 방법 3은 람다를 통해
x와y를 곱하라는 규칙을 즉석에서 전달했습니다.reduce는 [1, 2, 3, 4, 5]를 가지고 (12) -> (23) -> (64) -> (245) 순으로 계산해 최종적으로 120을 만들어냅니다.
3. 실무 활용 꿀팁: 정렬(Sorting)의 치트키
사실 실무에서 람다를 가장 많이 쓰는 곳은 map이나 filter보다 sort()나 sorted() 함수의 key 인자입니다.
예를 들어, 이름과 나이가 들어있는 튜플 리스트가 있을 때, 나이순으로 정렬하고 싶다면 어떻게 해야 할까요? 그냥 sort()를 쓰면 이름순으로 정렬됩니다. 이때 람다가 구원투수로 등장합니다.
people = [('김철수', 30), ('이영희', 20), ('박민수', 25)]
# 나이(튜플의 두 번째 요소인 index 1)를 기준으로 정렬해라!
people.sort(key=lambda x: x[1])
print(f"나이순 정렬 결과: {people}")
# 결과: [('이영희', 20), ('박민수', 25), ('김철수', 30)]
이 짧은 한 줄이 없다면, 여러분은 정렬을 위해 복잡한 클래스를 만들거나 별도의 함수를 정의해야 했을 겁니다. 정말 효율적이지 않나요?
💡 초보자 폭풍 질문!
Q: 재준봇님! 람다가 이렇게 편한데, 그냥 모든 함수를 람다로 만들면 안 되나요?
A: 오, 아주 날카로운 질문입니다! 하지만 절대 안 됩니다. 람다는 말 그대로 ‘일회용’입니다. 람다식은 이름이 없기 때문에, 나중에 다른 곳에서 다시 호출해서 쓸 수 없습니다. 또한, 람다식은 오직 한 줄의 표현식만 가질 수 있어요. 복잡한 로직, 조건문이 여러 개 들어가는 기능, 여러 줄의 코드가 필요한 경우에는 반드시 def를 사용해 정식 함수를 만들어야 합니다. 람다는 ‘가벼운 간식’ 같은 것이고, def는 ‘정식 코스 요리’ 같은 것이라고 생각하세요!
⚠️ 실무 주의보
주의: 람다식을 너무 남발하면 가독성이 쓰레기가 됩니다!
내용: 가끔 코드를 아주 짧게 쓰고 싶어서 map 안에 filter를 넣고, 그 안에 또 람다를 넣는 분들이 계십니다. 이렇게 되면 코드는 한 줄이 되지만, 나중에 본인이 짠 코드를 봐도 “이게 대체 뭐 하는 코드지?”라며 멍해지는 상황이 발생합니다.
해결책:
- 람다식은 한 줄로 끝낼 수 있는 아주 단순한 로직에만 사용하세요.
- 식이 조금만 복잡해진다 싶으면 주저하지 말고
def로 정식 함수를 만드세요. - 동료 개발자가 봤을 때 3초 안에 이해되지 않는 람다식은 실패한 코드입니다. 가독성이 효율성보다 훨씬 중요합니다!
마무리하며
오늘 우리는 파이썬의 고수들이 사랑하는 람다식과 고차 함수에 대해 깊게 파헤쳐 보았습니다.
- 람다식: 이름 없는 일회용 함수.
- 고차 함수: 함수를 인자로 받거나 반환하는 함수 (
map,filter,reduce). - 핵심: 적재적소에 사용하여 코드의 간결함을 추구하되, 가독성을 해치지 말 것!
처음에는 람다식의 lambda x: x * 2 같은 문법이 낯설겠지만, 계속 쓰다 보면 어느새 손가락이 먼저 움직이는 여러분을 발견하게 될 겁니다. 오늘 배운 내용을 직접 코드로 구현해 보시면서 여러분의 것으로 만드시길 바랍니다.
다음 강의에서는 더욱 강력한 파이썬의 기능으로 돌아오겠습니다. 고생 많으셨습니다!
<hr>