Python 중첩 딕셔너리(nested dictionary)는 딕셔너리 안에 또 다른 딕셔너리가 포함된 구조를 말합니다. 기존 딕셔너리 안에서도 키-값 매핑 구조를 그대로 활용해 데이터를 저장할 수 있다는 점이 특징입니다.
Python으로 딕셔너리를 다루다 보면 하나의 딕셔너리 안에 또 다른 딕셔너리를 담아야 하는 상황을 자주 마주하게 됩니다.
이러한 데이터 구조는 흔히 중첩 딕셔너리라고 부르며, 실무 Python 코드에서 다양하게 활용됩니다.
이 튜토리얼에서는 Python 중첩 딕셔너리의 기본 개념을 살펴보고, 몇 가지 예제를 통해 중첩 딕셔너리를 만들고 수정하는 방법까지 단계별로 알아보겠습니다.
Python 딕셔너리 복습
딕셔너리는 Python의 대표적인 매핑(mapping) 데이터 타입입니다. Python 딕셔너리는 키(key)와 값(value)을 연결하거나 매핑하여 데이터를 효율적으로 저장할 수 있게 해줍니다.
키가 값에 매핑되어 있으면, 해당 키만 참조하면 저장된 데이터를 손쉽게 꺼낼 수 있습니다. 즉, 키는 일종의 라벨처럼 동작하는 셈입니다. 아래는 동네 아이스크림 가게 'The Frozen Spoon'에서 판매하는 아이스크림 맛별 가격을 담은 딕셔너리 예시입니다.
ice_cream_flavors = {
"Vanilla": 0.50,
"Chocolate": 0.50,
"Cookies and Cream": 0.75,
"Strawberry": 0.65,
"Buttered Pecan": 0.90
}
이 딕셔너리에서 키는 아이스크림 이름(예: "Vanilla")이고, 값은 각 맛의 스쿱당 가격입니다.
Python 중첩 딕셔너리란?
Python 중첩 딕셔너리는 딕셔너리 안에 딕셔너리가 들어 있는 구조입니다. 하나의 큰 딕셔너리 안에 여러 개의 하위 딕셔너리를 담는 데 사용되며, 원한다면 몇 겹이든 자유롭게 중첩할 수 있습니다.
중첩 딕셔너리는 여러 개의 작은 딕셔너리를 하나의 큰 딕셔너리로 묶어 관리하고 싶을 때 특히 유용합니다.
간단한 예제를 통해 중첩 딕셔너리가 어떻게 동작하는지 살펴보겠습니다. The Frozen Spoon에서 판매하는 각 아이스크림 맛에 대한 정보를 딕셔너리로 만들어, 이를 다시 하나의 큰 딕셔너리에 담고 싶다고 가정해 봅시다. 각 하위 딕셔너리에는 다음 정보가 들어갑니다.
- 아이스크림 이름
- 가격
- 재고(파인트) 수량
이 데이터를 담는 중첩 딕셔너리는 다음과 같은 형태가 됩니다.
ice_cream_flavors = {
0: { "flavor": "Vanilla", "price": 0.50, "pints": 20 },
1: { "flavor": "Chocolate", "price": 0.50, "pints": 31 },
2: { "flavor": "Cookies and Cream", "price": 0.75, "pints": 14 }
}
위 코드에서는 ice_cream_flavors라는 하나의 큰 딕셔너리를 선언했습니다. 이 딕셔너리에는 세 개의 딕셔너리가 들어 있으며, 각각 특정 아이스크림 맛에 대한 정보를 저장하고 있습니다.
중첩 딕셔너리를 사용하지 않았다면 이 정보들을 서로 다른 변수에 나눠 저장했어야 합니다. 그런데 모든 딕셔너리가 결국 아이스크림 맛에 대한 정보라는 점을 고려하면, 이런 방식은 직관적이지 않습니다.
중첩 딕셔너리 항목 접근하기
중첩 딕셔너리의 항목에 접근하려면 인덱싱 문법을 사용하면 됩니다.
예를 들어, 딕셔너리에서 인덱스 값이 0인 아이스크림의 가격을 조회하고 싶다면 다음 코드를 사용할 수 있습니다.
ice_cream_flavors = {
0: { "flavor": "Vanilla", "price": 0.50, "pints": 20 },
1: { "flavor": "Chocolate", "price": 0.50, "pints": 31 },
2: { "flavor": "Cookies and Cream", "price": 0.75, "pints": 14 }
}
print(ice_cream_flavors[0]["price"])
print(ice_cream_flavors[0]["flavor"])
실행 결과는 다음과 같습니다.
0.50 Vanilla
위 코드에서는 먼저 큰 딕셔너리에서 가져오려는 값의 키를 지정했습니다. 여기서는 인덱스 값이 0인 레코드에 접근했습니다.
그다음에는 내부 딕셔너리에서 꺼내고자 하는 항목의 이름을 지정했습니다. 이번 예제에서는 아이스크림의 가격과 맛을 알고 싶었기 때문에 두 개의 print() 문에 각각 price와 flavor를 지정한 것입니다.
Python 중첩 딕셔너리: 요소 추가하기
중첩 딕셔너리에 요소를 추가할 때는 기존 항목을 수정할 때와 같은 문법을 사용합니다. 중첩 딕셔너리에 항목을 추가하는 전용 메서드는 따로 없으며, 할당 연산자(=)를 사용해야 합니다.
항목 추가 문법은 다음과 같습니다.
dictionary_name[new_key_name] = new_value
판매 중인 바닐라 아이스크림 정보를 담은 딕셔너리가 있고, 할인 여부를 추적하고 싶다고 가정해 봅시다. 다음 코드로 처리할 수 있습니다.
ice_cream_flavors = {
0: { "flavor": "Vanilla", "price": 0.50, "pints": 20 },
1: { "flavor": "Chocolate", "price": 0.50, "pints": 31 },
2: { "flavor": "Cookies and Cream", "price": 0.75, "pints": 14 }
}
ice_cream_flavors[0]["discount"] = True
print(ice_cream_flavors[0])
코드를 실행해 결과를 확인해 보겠습니다.
{'flavor': 'Vanilla', 'price': 0.5, 'pints': 20, 'discount': True}
딕셔너리는 Python 변수 "ice_cream_flavors"에 저장되어 있습니다.
우리는 이 딕셔너리에 discount라는 새 키를 추가했습니다. 이 키의 인덱스 위치는 0이며, 값을 True로 설정했습니다. 그런 다음 ice_cream_flavors 중첩 딕셔너리에서 인덱스 값이 0인 딕셔너리를 출력해 discount 키가 정상적으로 추가되었음을 확인했습니다.
같은 문법으로 기존 딕셔너리의 요소를 업데이트할 수도 있습니다. 예를 들어 초콜릿 아이스크림 가격을 스쿱당 $0.45로 변경하고 싶다면 다음 코드를 사용하면 됩니다.
ice_cream_flavors = {
0: { "flavor": "Vanilla", "price": 0.50, "pints": 20 },
1: { "flavor": "Chocolate", "price": 0.50, "pints": 31 },
2: { "flavor": "Cookies and Cream", "price": 0.75, "pints": 14 }
}
ice_cream_flavors[1]["price"] = 0.45
print(ice_cream_flavors[1])
실행 결과는 다음과 같습니다.
{'flavor': 'Chocolate', 'price': 0.45, 'pints': 31}
초콜릿 아이스크림의 price 키 값이 $0.45로 변경되었습니다.
이렇게 하려면 price 값을 수정하고자 하는 딕셔너리의 인덱스 값을 1로 지정합니다. 이 값은 딕셔너리에서 초콜릿 아이스크림 정보를 담고 있는 항목입니다. 그런 다음 price 키에 새 값을 할당한 것입니다.
Python 중첩 딕셔너리: 요소 삭제하기
중첩 딕셔너리에 저장된 항목을 삭제하려면 del 문을 사용할 수 있습니다. del 문은 객체를 삭제할 때 사용하며, Python의 break 문처럼 한 줄에 독립적으로 작성하고 그 뒤에 삭제할 딕셔너리 항목을 적으면 됩니다.
가게에서 쿠키 앤 크림 아이스크림 판매를 잠시 중단했다고 가정해 봅시다. 쿠키 앤 크림을 보관하던 냉동고가 고장 나면서 제품이 녹아버린 상황입니다.
다음 코드로 이 아이스크림을 중첩 딕셔너리에서 제거할 수 있습니다.
ice_cream_flavors = {
0: { "flavor": "Vanilla", "price": 0.50, "pints": 20 },
1: { "flavor": "Chocolate", "price": 0.50, "pints": 31 },
2: { "flavor": "Cookies and Cream", "price": 0.75, "pints": 14 }
}
del ice_cream_flavors[2]
print(ice_cream_flavors)
실행 결과는 다음과 같습니다.
{0: {'flavor': 'Vanilla', 'price': 0.5, 'pints': 20}, 1: {'flavor': 'Chocolate', 'price': 0.5, 'pints': 31}}
위 코드에서는 del 문을 사용해 중첩 딕셔너리에서 키가 2인 항목을 삭제했습니다. 실행 결과를 보면 Cookies and Cream 항목이 중첩 딕셔너리에서 사라진 것을 확인할 수 있습니다.
Python 중첩 딕셔너리 순회하기
이번에는 중첩 딕셔너리에 있는 각 딕셔너리의 내용을 콘솔에 출력하고 싶다고 가정해 봅시다. 어떻게 하면 될까요?
좋은 질문입니다. 중첩 딕셔너리의 내용을 출력하려면 Python for 반복문으로 순회하면 됩니다. 여기에 더해 Python 딕셔너리의 items() 메서드를 활용해 딕셔너리의 키와 값 목록을 함께 가져올 수 있습니다.
ice_cream_flavors = {
0: { "flavor": "Vanilla", "price": 0.50, "pints": 20 },
1: { "flavor": "Chocolate", "price": 0.50, "pints": 31 },
2: { "flavor": "Cookies and Cream", "price": 0.75, "pints": 14 }
}
for key, value in ice_cream_flavors.items():
print("Ice Cream:", key)
for k, v in value.items():
print(k + ":", value[k])
실행 결과는 다음과 같습니다.
Ice Cream: 0 flavor: Vanilla price: 0.5 pints: 20 Ice Cream: 1 flavor: Chocolate price: 0.5 pints: 31 Ice Cream: 2 flavor: Cookies and Cream price: 0.75 pints: 14
코드를 하나씩 살펴보겠습니다. 먼저 아이스크림 맛에 대한 중첩 딕셔너리를 정의했습니다.
그다음 ice_cream_flavors 딕셔너리의 각 키와 값을 순회하는 for 반복문을 작성했습니다. 이 반복문은 .items()를 사용해 ice_cream_flavors 딕셔너리의 모든 키와 값 목록을 생성하고, 그 목록 위를 순회합니다.
그런 다음 Ice Cream:이라는 문구 뒤에 해당 아이스크림에 연결된 키를 출력합니다.
마지막으로, 또 다른 for 반복문을 사용해 중첩 딕셔너리의 각 value(즉, 바닐라나 초콜릿처럼 내부에 있는 개별 항목)의 모든 요소를 순회합니다. 이 반복문은 내부 딕셔너리의 각 키 이름을 출력하고, 콜론(:)을 붙인 뒤 그 키에 연결된 값을 이어서 출력합니다.
마치며
중첩 딕셔너리를 사용하면 Python에서 딕셔너리 안에 딕셔너리를 저장할 수 있습니다.
이 튜토리얼에서는 예제와 함께 다음 방법들을 살펴보았습니다.
- 중첩 딕셔너리 생성하기
- 중첩 딕셔너리에 요소 추가 및 업데이트하기
- 중첩 딕셔너리에서 요소 삭제하기
- 중첩 딕셔너리 순회하기
Python 코딩을 더 깊이 배우고 싶다면 'How to Code in Python' 가이드를 참고해 보세요.