한마디 요약

lambda 는 “이름 없는 한 줄짜리 익명 함수(anonymous function)“. 순회 함수(iteration / higher-order function, 고차 함수)sorted, max, min, map, filter, reduce 와 짝지어 “여러 원소 중 뭘 기준으로 삼을지”를 간결히 지정할 때 쓴다. AI Agent 개발에서는 LangChain 의 RunnableLambda, 검색 결과 정렬, 도구 후보 필터링, Annotated[..., lambda ...] 같은 곳에 자주 등장.


대표 예시로 감 잡기

# 캐릭터 이름순 정렬 (출력 순서 고정)
sorted_results = sorted(GLOBAL_RESULTS, key=lambda x: x['character'])

lambda 를 쓴 이유: “리스트 안 여러 데이터 중 어떤 키를 기준으로 정렬할지” 를 Python 에게 간결히 알려주기 위해서.


1. 왜 정렬 기준이 필요한가

현재 GLOBAL_RESULTS 구조:

GLOBAL_RESULTS = [
    {"character": "사트라", "results": [...]},
    {"character": "레티아", "results": [...]},
    {"character": "루파메스", "results": [...]},
]

sorted(GLOBAL_RESULTS) 만 쓰면 Python 은 “딕셔너리들을 뭘 기준으로 줄 세우지? 이름순? 결과 개수순?” 당황한다. 그래서 “딕셔너리 안 character 값으로 가나다 정렬” 을 명시해줘야 한다.


2. lambda 문법

# 기본형
lambda 파라미터: 반환값
 
# 일반 함수로 대응
def _(파라미터):
    return 반환값

의미 해부:

  • lambda x: x['character']
    • x: 리스트의 원소 한 덩어리 (딕셔너리 하나)
    • x['character']: character 키에 해당하는 값 (예: “레티아”)

lambda 없이 쓰려면

def get_name(item):
    return item['character']
 
sorted_results = sorted(GLOBAL_RESULTS, key=get_name)

정렬 한 번 하려고 함수를 매번 정의해야 하니 코드가 길어진다. lambda 는 이걸 한 줄로 압축.


3. x 는 어디서 오는가 (컨베이어 벨트 비유)

sorted(GLOBAL_RESULTS, key=lambda x: x['character']) 가 실행되면:

  1. 컨베이어 벨트 작동: GLOBAL_RESULTS 상자들이 벨트 위에 올라감
  2. 검사관 배치: lambda x: ... 는 벨트 옆의 검사관
  3. 하나씩 검사: 상자 한 개가 x 로 넘어옴 → 검사관이 “이 상자 이름은 ‘레티아’” 기록
  4. 전체 비교: 모든 상자의 이름을 수집한 뒤 가나다순으로 재배치

내부 동작 상상도

# 실제 Python 이 하는 일
결과 = []
for 아이템 in GLOBAL_RESULTS:
    기준값 = (lambda x: x['character'])(아이템)   # x = 아이템
    # 기준값으로 순서 결정

x = 선언이 필요 없는 이유: sorted 같은 고차 함수가 “내가 for 문 돌면서 원소 하나씩 네 함수에 넣어줄게” 라고 이미 약속해둠.


4. 짝꿍: 대표적인 순회(고차) 함수들

고차 함수(higher-order function) = 함수를 인자로 받거나 함수를 반환하는 함수. lambda 의 주 활동 무대.

함수용도예시
sorted(iter, key=...)정렬sorted(items, key=lambda x: x.score)
max(iter, key=...)최댓값max(results, key=lambda x: x['score'])
min(iter, key=...)최솟값min(results, key=lambda x: x['score'])
map(func, iter)각 원소 변환map(lambda x: x*2, nums)
filter(func, iter)조건 통과만 남김filter(lambda x: x>0, nums)
functools.reduce(func, iter)누적 합산reduce(lambda a,b: a+b, nums, 0)
any / all조건 집계any(lambda ...) 은 불가, 제너레이터 써야 함

포함 관계

고차 함수 (higher-order function)
├─ 내장: sorted, max, min, map, filter, any, all, sum, zip
├─ functools: reduce, partial, lru_cache, wraps
└─ 외부: LangChain RunnableLambda, pandas apply, ...

lambda 는 이 모든 함수에 “기준 규칙” 을 넣는 즉석 표현식 으로 쓰인다.


5. 자주 쓰는 패턴 8개

패턴 A. 딕셔너리 키 기준 정렬

users = [{"name": "A", "age": 30}, {"name": "B", "age": 25}]
sorted(users, key=lambda u: u["age"])
# [{'name': 'B', 'age': 25}, {'name': 'A', 'age': 30}]

패턴 B. 여러 키로 다단계 정렬 (튜플)

# 부서순 → 같은 부서면 연봉 내림차순
sorted(emps, key=lambda e: (e["dept"], -e["salary"]))

패턴 C. 역순 정렬

sorted(items, key=lambda x: x.score, reverse=True)

패턴 D. map 으로 일괄 변환

scores = [80, 90, 75]
ratios = list(map(lambda s: s / 100, scores))   # [0.8, 0.9, 0.75]

패턴 E. filter 로 선별

tools = [...]
callable_tools = list(filter(lambda t: t.is_enabled, tools))

패턴 F. 복수 기준 점수화 → max

docs = [...]
best = max(docs, key=lambda d: d["relevance"] * 0.7 + d["recency"] * 0.3)

패턴 G. reduce 로 누적

from functools import reduce
total_tokens = reduce(lambda acc, msg: acc + len(msg.content), messages, 0)

패턴 H. 조건 함수 즉석 생성 (클로저 결합)

def make_above(threshold):
    return lambda x: x > threshold
 
above_70 = make_above(70)
list(filter(above_70, scores))

lambda클로저(Closure)란 와 자연스럽게 결합된다.


6. lambda 를 쓰면 안 되는 경우 (트레이드오프)

쓰기 좋음쓰지 말 것
한 줄로 표현되는 변환if/else 가 복잡해 가독성 떨어지는 경우
sorted/max/filter 의 key 인자여러 번 재사용하는 로직 (이름 붙여 def 로)
짧은 콜백타입 힌트가 중요한 공개 API (lambda 는 힌트 못 붙임)

lambda 의 제약

  • 한 줄짜리 표현식만 가능. return, try, if 문(statement) 불가. 삼항 x if cond else y 는 표현식이라 OK.
  • 타입 힌트 붙일 수 없음. Callable[..., X] 로 힌트 주거나 def 를 쓴다.
  • 이름이 없음. 스택 트레이스에 <lambda> 로만 찍혀서 디버깅이 조금 불편.
# 가능
f = lambda x: "big" if x > 10 else "small"
 
# 불가능 (여러 줄 / 문 포함)
# f = lambda x: 
#     if x > 10: return "big"
#     else: return "small"

7. AI Agent 코드에서의 쓰임

쓰임 1: LangChain RunnableLambda 로 체인 연결

from langchain_core.runnables import RunnableLambda
 
to_upper = RunnableLambda(lambda x: x.upper())
chain = prompt | llm | to_upper

함수 객체로 체인에 끼워 넣어야 하는 자리에 lambda 가 간결. 함수의 반환값을 파라미터로 넣기 의 괄호 없는 전달과 같은 결.

쓰임 2: LangGraph Annotated 의 reducer

from typing import Annotated, TypedDict
 
class State(TypedDict):
    counters: Annotated[dict, lambda old, new: {**old, **new}]
    # 두 dict 를 merge 하는 reducer 를 lambda 로 즉석 주입

쓰임 3: 도구 후보 정렬 / 필터링

tools = load_all_tools()
relevant = sorted(
    filter(lambda t: t.category == "search", tools),
    key=lambda t: -t.priority,
)

쓰임 4: LLM 응답 후처리

results = [...]   # 검색 결과
top3 = sorted(results, key=lambda r: r["score"], reverse=True)[:3]

8. 성능 얘기 (가볍게)

lambdadef 의 런타임 성능은 동일. 둘 다 함수 객체가 만들어지고 호출된다. def 쪽이 이름이 있어 디버깅만 유리할 뿐.

list(map(lambda x: x*2, nums)) 과 리스트 컴프리헨션 [x*2 for x in nums] 을 비교하면, 컴프리헨션이 대체로 더 빠르고 읽기 좋다. 단순 변환은 컴프리헨션을 먼저 고려.

# 선호
doubled = [x * 2 for x in nums]
 
# 대안 (가독성↓, 성능도 비슷하거나 약간 느림)
doubled = list(map(lambda x: x * 2, nums))

단, sorted(key=...), max(key=...) 처럼 함수 객체를 꼭 넘겨야 하는 자리에서는 lambda 가 최선.


9. 면접용 한 줄 답변

“리스트 내의 딕셔너리 구조에서 특정 키값을 기준으로 정렬하기 위해, sorted 함수의 key 인자에 익명 함수를 전달하여 간결하게 구현했습니다.”


관련 문서


한마디 재요약

lambda“한 줄 함수 즉석 쓰고 버리기” 용 도구. 고차 함수(sorted, map, filter 등) 와 결합할 때 가장 빛난다. Agent 코드에서 체인·리듀서·정렬 기준을 짧게 박아 넣을 때 손에 붙여두면 편한 문법.