lambda는 이름을 붙이지 않고 그 자리에서 만드는 작은 함수입니다. 함수도 값이라 다른 함수에 넘길 수 있고, sorted()·max()에 key=로 넘긴 함수는 값마다 불려 정렬 기준이 됩니다.
정렬: sort와 sorted의 sorted는 값 자체를 견줘 가나다 차례나 작은 수부터 놓았습니다. 메뉴를 글자 수나 가격 차례로 놓으려면, 값마다 무엇을 견줄지 정하는 함수를 key로 넘깁니다.
그 함수가 한 번만 쓰는 작은 함수라면 def로 이름을 붙이는 대신 그 자리에서 lambda로 만듭니다.
1정렬 기준 함수는 sorted가 부른다
그림의 첫 장면 코드입니다.
menu = ['녹차', '카푸치노', '라테']
short = sorted(menu, key=len)
print(short)
['녹차', '라테', '카푸치노']2번 줄의 key=len은 len을 부르지 않고 넘깁니다. 함수 만들고 부르기에서 본 것처럼 괄호 없는 이름 len은 함수 그 자체를 가리킵니다. 함수도 값이라 이름이 붙고 다른 함수에 넘길 수 있습니다(규칙 3).
넘겨받은 sorted가 값마다 len을 불러 2, 4, 2를 얻습니다. 이렇게 sorted가 견주려고 얻는 값을 이 레슨은 key 값이라고 부릅니다.
sorted는 key 값이 작은 차례로 원래 값을 놓은 새 리스트를 돌려줍니다. 돌려주는 것은 key 값이 아니라 원래 값이고, menu의 리스트는 그대로입니다.
2def로 만든 기준 함수와 lambda
가격 차례로 놓으려면 이름을 받아 가격을 돌려주는 함수가 있어야 합니다. def로 만들면 이렇습니다.
won = {'커피': 4000, '녹차': 3500}
def price(name):
return won[name]
cheap = sorted(won, key=price)
print(cheap)
['녹차', '커피']sorted가 키마다 price를 부르고, 부를 때마다 함수 만들고 부르기의 그림처럼 칸이 생깁니다. 몸의 won은 price 칸에 없어 전역 칸에서 찾습니다(규칙 5).
그림의 둘째 장면은 같은 함수를 lambda name: won[name]으로 그 자리에서 만들어 넘겼습니다. lambda 다음이 매개변수, 콜론 뒤가 식 하나입니다. return을 쓰지 않아도 그 식의 값을 돌려주고, 거꾸로 lambda 안에 return을 쓰면 SyntaxError입니다.
lambda도 부를 때마다 칸이 생기는 함수입니다. 그림은 그 칸을 식 한 줄로 줄여 그렸습니다. 자료에 따라 람다 함수나 익명 함수라고도 부릅니다.
lambda에 이름을 붙여 쓰는 코드도 만납니다.
double = lambda n: n * 2
print(double(4))
8double은 def로 만든 함수처럼 부릅니다. 이름을 붙여 둘 함수라면 직접 쓸 때는 def로 씁니다 — 파이썬 문서(PEP 8)가 권하는 꼴입니다.
3key 값이 같으면 원래 차례
글자 수가 같은 메뉴가 둘 있습니다. 무엇이 찍힐까요?
menu = ['라테', '카푸치노', '녹차']
print(sorted(menu, key=len))
실행 결과 보기
['라테', '녹차', '카푸치노']예상과 다르면 그곳이 배울 곳입니다. ['녹차', '라테', '카푸치노']를 예상했다면, key 값이 같을 때 가나다 차례로 놓인다고 본 것입니다.
sorted는 key 값만 견줍니다. '라테'와 '녹차'는 key 값이 둘 다 2라 견줄 것이 없어, 원래 리스트의 차례대로 '라테'가 앞에 남습니다.
예제
가격 차례로 정렬하기
메뉴 셋을 싼 것부터 놓습니다. 딕셔너리는 한 줄에 한 쌍씩 나눠 썼습니다.
won = {
'커피': 4000,
'라테': 4500,
'녹차': 3500,
}
cheap = sorted(
won,
key=lambda name: won[name],
)
print(cheap)
['녹차', '커피', '라테']sorted가 키마다 lambda를 불러 가격을 key 값으로 얻고, 그 값이 작은 차례로 키를 놓습니다.
가장 긴 이름 찾기
max에도 key를 넘길 수 있습니다. 무엇이 찍힐까요?
menu = ['녹차', '카푸치노', '라테']
print(max(menu, key=len))
실행 결과 보기
카푸치노예상과 다르면 그곳이 배울 곳입니다. 4를 예상했다면, max가 key 값을 돌려준다고 본 것입니다. max도 key 값이 가장 큰 원래 값을 돌려줍니다. 가장 큰 것이 여럿이면 앞에 있는 것입니다.
자주 틀리는 곳
틀린 생각: 함수를 key로 넘길 때도 이름 뒤에 괄호를 붙여야 한다.
함수를 쓸 때는 늘 괄호를 붙여 불렀으니, 넘길 때도 붙여야 할 것 같습니다. 괄호를 붙이면 그 자리에서 부릅니다.
a = ['카푸치노', '녹차']
print(sorted(a, key=len))
b = sorted(a, key=len())
['녹차', '카푸치노']Traceback (most recent call last): File "main.py", line 3, in <module> b = sorted(a, key=len()) ~~~^^TypeError: len() takes exactly one argument (0 given)맨 아래 줄은 'len은 인자 하나를 받아야 하는데 0개를 받았다'는 뜻입니다. 3번 줄의 len()이 sorted에 넘어가기 전에 인자 없이 불린 것입니다.
맞는 규칙: 괄호를 붙이면 그 자리에서 부르고 그 결과를 넘깁니다. 함수를 넘겨 sorted가 부르게 하려면 key=len처럼 이름만 씁니다(규칙 5).
틀린 생각: sorted와 max는 key가 돌려준 값을 결과로 돌려준다.
견주는 것이 key 값이니 결과도 key 값일 것 같습니다. key 값은 차례를 정하는 데만 쓰입니다.
a = ['카푸치노', '녹차']
print(sorted(a, key=len))
print(max(a, key=len))
['녹차', '카푸치노']
카푸치노sorted는 [2, 4]가 아니라 원래 값을 그 차례로 놓은 리스트를, max는 4가 아니라 '카푸치노'를 돌려줍니다.
맞는 규칙: key로 넘긴 함수가 낸 값은 견주는 데만 쓰이고, sorted와 max는 원래 값을 돌려줍니다.
틀린 생각: key 값이 같으면 가나다 차례로 놓인다.
key 없이 정렬하면 가나다 차례였으니, key 값이 같을 때도 그럴 것 같습니다. sorted는 key 값만 견줍니다.
a = ['쿠키', '라테']
print(sorted(a))
print(sorted(a, key=len))
['라테', '쿠키']
['쿠키', '라테']key가 없는 2번 줄은 값 자체를 견줘 가나다 차례입니다. 3번 줄은 key 값이 둘 다 2라 원래 차례 그대로입니다.
맞는 규칙: sorted는 key 값만 견주고, key 값이 같은 값끼리는 원래 리스트의 차례를 바꾸지 않습니다. 그래서 key 값이 같은 값끼리의 차례는 원래 리스트에서 읽습니다.
확인 문제
1. 그림 둘째 장면 코드에서 커피 값을 3000으로 바꾸고, cheap을 찍는 줄을 더했습니다. 무엇이 찍힐까요?
won = {'커피': 3000, '녹차': 3500}
cheap = sorted(
won,
key=lambda name: won[name],
)
print(cheap)
힌트
4번 줄의 lambda가 키마다 돌려주는 값을 먼저 적고, 그 값의 차례로 키를 놓습니다.
정답
['커피', '녹차']lambda가 '커피'에 3000, '녹차'에 3500을 돌려주어 작은 key 값의 '커피'가 앞입니다.
흔한 오답은 ['녹차', '커피']입니다. key를 넘겨도 키 글자의 가나다 차례로 놓인다고 본 것입니다. [3000, 3500]이라고 썼다면 sorted가 key 값을 돌려준다고 본 것입니다.
2. 판매 수가 적은 메뉴부터 놓으려 합니다. 빈칸을 채우세요. 다 채운 코드는 ['라테', '커피']를 찍고, 라테의 판매 수를 15로 바꾸면 ['커피', '라테']를 찍어야 합니다.
sold = {'커피': 12, '라테': 7}
few = sorted(
sold,
key=lambda name: ____,
)
print(few)
힌트
lambda는 키 하나를 받아, 그 키로 견줄 값을 돌려주는 식 하나입니다. 견줄 값은 판매 수입니다.
정답
sold[name]입니다. lambda가 키마다 판매 수를 돌려주어, 7인 '라테'가 12인 '커피'보다 앞에 놓여 ['라테', '커피']가 찍힙니다.
다르게 써도 되는 곳: sold.get(name)도 같은 값을 돌려줍니다.
흔한 오답은 name입니다. 키 글자 자체를 견줘 가나다 차례가 되므로 처음 값으로는 ['라테', '커피']가 맞아 보이지만, 라테를 15로 바꿔도 ['라테', '커피'] 그대로라 틀린 것이 드러납니다. name이 키가 아니라 판매 수에 붙는다고 본 것입니다. return sold[name]처럼 return을 쓰면 SyntaxError입니다.
3. 요일마다 걸은 걸음 수에서 가장 많이 걸은 요일을 찍습니다. 무엇이 찍힐까요?
steps = {'월': 6500, '화': 4000}
best = max(
steps,
key=lambda day: steps[day],
)
print(f'{best}요일')
힌트
max가 요일마다 lambda를 불러 얻는 key 값을 적고, max가 무엇을 돌려주는지 봅니다.
정답
월요일key 값은 월 6500, 화 4000이라 key 값이 가장 큰 '월'을 max가 돌려줍니다.
흔한 오답은 6500요일입니다. max가 key 값을 돌려준다고 본 것입니다. 화요일이라고 썼다면 key를 넘겨도 요일 글자 자체를 견준다고 본 것입니다.
예제 코드의 8번 줄을 key=lambda name: -won[name],으로 바꾸면 무엇이 찍히는지 봅니다.
처음 펼 때 약 6MB를 받습니다.컴퓨터에서 해 보기
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.
더 보기: 같은 정렬은 sorted(won, key=won.get)으로도 됩니다. 딕셔너리의 get 메서드를 괄호 없이 넘긴 것입니다(딕셔너리: 키로 찾기). 다른 자료에서 lambda를 map·filter와 함께 쓰는 코드도 만나는데, 이 과목은 같은 일을 리스트 컴프리헨션으로 합니다.