리스트 안의 딕셔너리는 값 여럿을 묶은 딕셔너리를 리스트에 차례로 담은 것입니다. orders[1]['qty']처럼 바깥 리스트부터 한 겹씩 꺼냅니다.
주문 하나에는 메뉴와 수량처럼 값이 둘 이상입니다. 메뉴 리스트와 수량 리스트를 따로 두면 같은 자리 번호끼리 짝을 맞춰야 해서, 하나를 지우거나 차례를 바꾸면 짝이 어긋나기 쉽습니다. 주문 하나를 딕셔너리로 묶어 리스트에 담으면 한 주문의 값이 늘 함께 다닙니다.
1바깥부터 한 겹씩 꺼낸다
orders = [
{'item': '커피', 'qty': 2},
{'item': '라테', 'qty': 1},
]
second = orders[1]
print(second)
print(second['qty'])
print(orders[1]['qty'])
{'item': '라테', 'qty': 1}
1
11~4번 줄은 딕셔너리 둘을 담은 리스트를 만들고 이름 orders를 붙입니다. 5번 줄 orders[1]은 리스트의 1번 칸이 가리키는 딕셔너리이고, 7번 줄은 그 딕셔너리에서 키 'qty'의 값을 꺼냅니다.
8번 줄 orders[1]['qty']는 이 두 걸음을 한 줄로 쓴 것입니다. 왼쪽부터 orders[1]이 먼저 딕셔너리 하나가 되고, 그 딕셔너리에서 ['qty']를 꺼냅니다. 바깥은 리스트라 자리 번호로, 안쪽은 딕셔너리라 키로 꺼냅니다.
5번 줄은 새 딕셔너리를 만들지 않습니다. 1번 칸이 가리키는 바로 그 딕셔너리에 이름 second를 하나 더 붙입니다(규칙 3).
2칸은 딕셔너리를 가리킨다
리스트 레슨에서 칸 안의 수와 문자열은 칸에 바로 적었습니다. 정확히는 칸도 값을 가리킵니다. 그림은 바뀌는 값인 딕셔너리가 칸에 들면 칸에서 화살표를 그려, 리스트와 딕셔너리를 따로 보입니다.
그러면 리스트를 copy()로 복사할 때 무엇이 새로 생길까요? 무엇이 찍힐지 정한 뒤 펼쳐 보세요.
orders = [
{'item': '커피', 'qty': 2},
{'item': '라테', 'qty': 1},
]
backup = orders.copy()
orders[0]['qty'] = 3
print(backup[0]['qty'])
실행 결과 보기
3예상과 다르면 그곳이 배울 곳입니다.
copy()는 바깥 리스트만 새로 만듭니다. 새 리스트의 칸도 같은 딕셔너리를 가리켜서, orders[0]으로 바꾼 딕셔너리를 backup[0]으로 봐도 바뀌어 있습니다(규칙 3).
이렇게 한 겹만 새로 만드는 복사를 얕은 복사(shallow copy)라고 부릅니다.
3돌면서 꺼내기
for가 리스트의 칸을 하나씩 꺼내 order를 붙이면, order는 그 칸이 가리키는 딕셔너리입니다. 바퀴마다 키로 값을 꺼냅니다.
orders = [
{'item': '커피', 'qty': 2},
{'item': '라테', 'qty': 1},
]
for order in orders:
item = order['item']
print(item, order['qty'])
커피 2
라테 1예제
주문 합계 내기
메뉴판 딕셔너리에서 메뉴마다 가격을 꺼내 수량을 곱해 더합니다.
menu = {
'커피': 4000,
'라테': 4500,
}
orders = [
{'item': '커피', 'qty': 2},
{'item': '라테', 'qty': 1},
]
total = 0
for order in orders:
price = menu[order['item']]
qty = order['qty']
total = total + price * qty
print(total)
1250011번 줄은 대괄호 안의 order['item']을 먼저 계산해 '커피'를 얻고, 그 키로 menu['커피']가 4000을 꺼냅니다. 커피 2잔 8000원에 라테 4500원을 더해 12500입니다.
자주 틀리는 곳
틀린 생각: 바깥 리스트를 copy()하면 안의 딕셔너리도 새로 생긴다.
copy()가 리스트를 복사하니, 리스트에 든 것도 모두 새로 생길 것 같습니다. 새로 생기는 것은 바깥 리스트 하나입니다.
orders = [{'qty': 2}]
backup = orders.copy()
orders[0]['qty'] = 3
print(backup)
[{'qty': 3}]backup도 0번 칸이 orders와 같은 딕셔너리를 가리켜, 3으로 바뀐 수량이 보입니다.
맞는 규칙: copy()는 바깥 리스트만 새로 만들고, 새 리스트의 칸도 같은 딕셔너리를 가리킵니다. 안쪽 딕셔너리를 바꾸면 두 리스트 어느 쪽으로 봐도 바뀌어 있습니다(규칙 3).
틀린 생각: 리스트 안 딕셔너리의 값은 키만 대면 바로 꺼낼 수 있다.
'qty'를 찾으면 리스트 안 딕셔너리에서 알아서 찾아 줄 것 같습니다. 바깥은 리스트라 먼저 자리 번호로 딕셔너리 하나를 꺼내야 합니다.
orders = [
{'item': '커피', 'qty': 2},
{'item': '라테', 'qty': 1},
]
print(orders['qty'])
Traceback (most recent call last): File "main.py", line 5, in <module> print(orders['qty']) ~~~~~~^^^^^^^TypeError: list indices must be integers or slices, not str맨 아래 줄은 '리스트의 자리 번호는 정수나 자르기여야 하고 문자열은 안 된다'는 뜻입니다.
맞는 규칙: 바깥 리스트는 자리 번호로, 안쪽 딕셔너리는 키로 꺼냅니다. orders[1]['qty']처럼 바깥부터 한 겹씩 씁니다.
확인 문제
1. 1절 코드에서 5번 줄부터를 바꿨습니다. 무엇이 찍히는지 두 줄을 글자 그대로 쓰세요.
orders = [
{'item': '커피', 'qty': 2},
{'item': '라테', 'qty': 1},
]
last = orders[-1]
print(last['item'])
print(orders[0]['qty'] + 1)
힌트
바깥 리스트에서 어느 칸을 꺼내는지 먼저 정하고, 그 딕셔너리에서 키로 꺼냅니다.
정답
라테
3orders[-1]은 마지막 칸이 가리키는 라테 딕셔너리라서 last['item']은 라테입니다. orders[0]['qty']는 커피 딕셔너리의 수량 2이고, 1을 더해 3입니다.
흔한 오답은 첫 줄을 커피로 쓰는 것입니다. -1을 첫 칸으로 본 것입니다. 음수 번호는 뒤에서부터 셉니다.
2. 장바구니에 담은 과일 수를 모두 더해 5를 찍으려 합니다. 2번 줄의 배 수량이 4면 7이 찍혀야 합니다. 빈칸을 채우세요.
cart = [
{'name': '배', 'qty': 2},
{'name': '귤', 'qty': 3},
]
count = 0
for fruit in cart:
qty = ________
count = count + qty
print(count)
힌트
6번 줄에서 fruit가 무엇을 가리키는지 봅니다.
정답
fruit['qty']입니다.
cart = [
{'name': '배', 'qty': 2},
{'name': '귤', 'qty': 3},
]
count = 0
for fruit in cart:
qty = fruit['qty']
count = count + qty
print(count)5바퀴마다 fruit는 칸이 가리키는 딕셔너리라서, 키 'qty'로 수량을 꺼냅니다.
다르게 써도 되는 곳: fruit.get('qty', 0)도 같습니다.
흔한 오답은 cart['qty']입니다. 바깥 리스트에 키를 대어 TypeError로 멈춥니다. 키만 대면 리스트 안 딕셔너리의 값을 바로 꺼낼 수 있다고 본 것입니다. 안쪽 딕셔너리는 fruit입니다.
3. 장바구니 리스트를 copy()로 복사해 두고 원래 리스트를 고쳤습니다. 무엇이 찍히는지 두 줄을 글자 그대로 쓰세요.
cart = [
{'name': '사과', 'qty': 3},
{'name': '배', 'qty': 2},
]
saved = cart.copy()
cart[1]['qty'] = 5
extra = {'name': '귤', 'qty': 1}
cart.append(extra)
print(len(saved))
print(saved[1]['qty'])
힌트
6번 줄은 안쪽 딕셔너리를, 8번 줄은 바깥 리스트를 바꿉니다. 각각 saved와 같은 것인지 따로 봅니다.
정답
2
5copy()는 바깥 리스트를 새로 만들어서, 8번 줄이 cart에 더한 귤은 saved에 없습니다. 그래서 saved의 칸은 둘입니다. 안쪽 딕셔너리는 새로 생기지 않아 saved의 1번 칸도 cart와 같은 배 딕셔너리를 가리키므로, 6번 줄에서 바꾼 수량 5가 보입니다.
흔한 오답은 둘째 줄을 2로 쓰는 것입니다. copy()가 안쪽 딕셔너리까지 새로 만든다고 본 것입니다(복사된다는 생각). 새로 생기는 것은 바깥 리스트뿐입니다.
5번 줄 다음에 second['qty'] = 3을 더 쓰면 찍히는 줄을 모두 봅니다.
처음 펼 때 약 6MB를 받습니다.컴퓨터에서 해 보기
파이썬 3.14. Tab을 누르면 다음 단추나 칸으로 갑니다. 들여쓰기는 빈칸 네 개입니다. Enter는 앞줄 들여쓰기를 잇고, 콜론 뒤에서는 한 단계 더 들여 씁니다. Ctrl+Enter로 실행합니다.
'실행'을 누르면 여기에 나옵니다.
여기서 쓴 코드 · 내 예상은 저장하지도 운영자에게 보내지도 않습니다. 페이지를 새로 열면 처음 코드입니다.