파이썬 딕셔너리 자료구조 이해하기

딕셔너리란?
일반적으로 딕셔너리(사전)는 단어의 의미를 담고있는 책을 말한다. 사전에 각 항목에는 정의되는 단어와 그 단어의 뜻, 총 두 부분으로 나뉜다.
파이썬에서 딕셔너리는 리스트와 튜플과 마찬가지로 객체의 컬렉션을 저장한다. 하지만, 객체들을 배열에 저장하는 대신, 딕셔너리는 키-값 쌍(key-value pairs)라고 불리는 방식으로 정보를 저장한다. 즉, 딕셔너리의 각 객체는 키(key)와 값(value), 두 부분으로 나뉜다.
키-값 쌍의 키는 값 부분을 식별하는 고유한 이름이다. 영어 사전과 같이, 키는 정의된느 단어와 같고, 값은 단어의 정의와 같다. 예를 들어, 다음과 같이 주(state)와 주도(capital)의 이름을 저장하기 위해 딕셔너리를 사용할 수 있다.

영어 사전에서 정의하는 딕셔너리와 파이썬에서의 딕셔너리가 다른 점은 키와 값의 관계가 완전히 임의적(arbitrary)이라는 것이다. 즉, 다음 예제처럼 모든 키를 모든 값에 할당할 수 있다.

위 예제에서 유일한 관계는 딕셔너리에서 각 키가 상응하는 값에 할당되었다는 것이다. 이런 관점에서, 파이썬의 딕셔너리는 영어 사전에서 정의하는 딕셔너리보다는 맵(map)에 훨씬 가깝다고 할 수 있다(맵이라는 용어는 값의 두 값의 집합간의 관계를 설명하는데 사용되는 수학 용어이다).
요약하자면, 파이썬 딕셔너리는 키 집합을 값 집합과 연결하는 자료구조이다. 각 키에는 두 집합 간의 관계를 정의하는 단일 값이 할당된다.
딕셔너리 생성하기
다음의 코드는 주와 주도를 담는 딕셔너리 리터럴(dictionary literal)을 생성한다.
>>> capitals = {
"California": "Sacramento",
"New York": "Albany",
"Texas": "Austin",
}
각 키는 값으로 부터 콜론(:
)으로 구분되고, 각 키-값 쌍은 콤마(,
)로 구분되며, 전체 딕셔너리는 중괄호({}
) 둘러 쌓인다.
또한 dict()
내장 함수를 사용해 튜플의 배열을 딕셔너리로 생성할 수 있다.
>>> key_value_pairs = (
... ("California", "Sacramento"),
... ("New York", "Albany"),
... ("Texas", "Austin"),
)
>>> capitals = dict(key_value_pairs)
딕셔너리를 호출하면 딕셔너리가 어떻게 생성 되었는지와는 상관없이 딕셔너리 리터럴로 표시된다.
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany', 'Texas': 'Austin'}
파이썬 3.6 버전을 사용한다면 위 예제와는 다른 출력값을 얻는다. 파이썬 3.6 버전 이전에는 딕셔너리 키-값 쌍의 순서가 랜덤이였기 때문이다. 이후 버전에서는 키-값 쌍의 순서가 처음에 삽입 되었을 때의 순서와 매치되도록 보장된다.
딕셔너리 이터럴이나 dict()
함수를 사용해 빈 딕셔너리를 생성할 수 있다.
>>> {}
{}
>>> dict()
{}
딕셔너리 값 접근하기
딕셔너리의 값에 접근하기 위해서는 딕셔너리 혹은 딕셔너리에 할당된 변수 이름 뒤에 대괄호로 접근하려는 키를 감싸주면 된다.
>>> capitals = {
"California": "Sacramento",
"New York": "Albany",
"Texas": "Austin",
}
>>> capitals["Texas"]
'Austin'
이전의 시퀀스 자료형과는 다르게 딕셔너리는 인덱스가 아닌 키를 사용해 값에 접근한다. 또한, 인덱스를 사용하지 않고 값에 접근하기 때문에 키를 사용할 때, 어떠한 순서도 정의되지 않는다.
딕셔너리에 값 추가 혹은 제거하기
딕셔너리 또한 리스트처럼 가변 자료구조이다. 즉, 항목을 추가하거나 제거할 수 있다.
다음 예제에서 콜로라도의 주도를 capitals
딕셔너리에 추가해보자.
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany', 'Texas': 'Austin'}
>>> capitals["Colorado"] = "Denver"
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany', 'Texas': 'Austin', 'Colorado': 'Denver'}
위처럼 새로운 값을 딕셔너리에 추가하기 위해서는 딕셔너리 뒤에 새로운 키 "Colorado"를 대괄호로 감싸 위치시키고, 할당 연산자 =
를 사용해 값 "Denver"를 새로운 키 "Colorado"에 할당해준다.
딕셔너리 안의 각 키는 단일 값으로만 할당될 수 있다. 만약 기존 키에 새로운 값이 주어지면, 파이썬은 기존 값을 덮어 쓴다.
>>> capitals["Texas"] = "Houston"
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany', 'Texas': 'Houston', 'Colorado': 'Denver'}
딕셔너리에서 항목을 지우기 위해서는 del
키워드를 키와 사용할 수 있다.
>>> del capitals["Texas"]
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany', 'Colorado': 'Denver'}
딕셔너리 키의 존재 확인하기
만약 딕셔너리에서 값에 접근하기 위해 존재하지 않는 키를 사용하면 파이썬은 KeyError
를 일으킨다.
>>> capitals["Arizona"]
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
capitals["Arizona"]
KeyError: 'Arizona'
in
키워드를 사용해서 딕셔너리 안의 키가 존재하는지 확인할 수 있다.
>>> "Arizona" in capitals
False
>>> "California" in capitals
True
in
키워드는 키의 존재여부만 체크한다는 점을 꼭 기억해야한다. "Sacramento"는 존재하는 키 "California"의 값이지만, 키가 아니기 때문에 False
가 반환된다.
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany', 'Colorado': 'Denver'}
>>> "Sacramento" in capitals
False
딕셔너리 반복하기
리스트와 튜플과 마찬가지로 딕셔너리는 반복 가능한 객체(iterable)이다. 하지만 딕셔너리를 반복하는 것은 리스트나 튜플을 반복하는 것과는 다르다.
딕셔너리를 반복할 때는 딕셔너리의 키를 사용해서 반복한다.
>>> for key in capitals:
... print(key)
...
California
New York
Colorado
만약 키와 값을 사용해 반복문을 작성하고 싶다면 다음과 같이 작성해야 한다.
>>> for state in capitals:
print(f"The capital of {state} is {capitals[state]}")
The capital of California is Sacramento
The capital of New York is Albany
The capital of Colorado is Denver
하지만, 파이썬에서는 items()
라고 불리는 딕셔너리 메서드를 사용해 더 간결하게 작성할 수 있다. items()
메서드를 사용하면 키-값 쌍의 튜플을 담고있는 리스트스러운 객체를 반환한다.
>>> capitals.items()
dict_items([('California', 'Sacramento'), ('New York', 'Albany'),
('Colorado', 'Denver')])
items()
메서드로 반환되는 객체는 사실 리스트는 아니다. dict_items
라고 불리는 특별한 타입을 가진다.
>>> type(capitals.items())
<class 'dict_items'>
items()
메서드는 딕셔너리의 키와 값을 동시에 반복하기 위해 사용될 수 있다. 위 예제에서 작성되었던 반복문을 아래처럼 다시 작성할 수 있다.
>>> for state, capital in capitals.items():
... print(f"The capital of {state} is {capital}")
The capital of California is Sacramento
The capital of New York is Albany
The capital of Colorado is Denver
capitals
딕셔너리에 items()
메서드를 사용함으로써, 반복문의 각 반복은 state
이름과, 키에 상응하는 capital
을 담는 튜플을 생산한다. 이 튜플을 state
와 capital
에 할당하면, 튜플의 구성요소가 두 변수 state
와 capital
에 언패킹 된다.
딕셔너리 키와 불변성
딕셔너리 captials
의 각 키는 문자열이다. 하지만 딕셔너리 키는 반드시 다 같은 자료형을 사용해야 한다와 같은 규칙은 존재하지 않는다. 예를 들어, 다음과 같이 딕셔너리 capitals에 정수형 키를 추가할 수도 있다.
>>> capitals[50] = "Honolulu"
>>> capitals
{'California': 'Sacramento', 'New York': 'Albany',
'Colorado': 'Denver', 50: 'Honolulu'}
유효한 딕셔너리 키를 제정하는 단 한 가지 규제가 존재하는데, 바로 불변 객체(immutable)만 허용된다는 점이다. 즉, 리스트와 같은 가변객체는 딕셔너리의 키가 될 수 없다.
>>> capitals[[1, 2, 3]] = "Bad"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
딕셔너리에서 유효한 키의 종류는 다음과 같다.

키와는 달리, 딕셔너리의 값은 유효한 모든 파이썬 타입을 사용할 수 있다!
중첩 딕셔너리
파이썬에서 리스트 안에 리스트를, 튜플 안에 튜플을 중첩할 수 있는 것처럼 중첩 딕셔너리 또한 생성할 수 있다. 기존 딕셔너리에서 주 이름과 주도를 매핑하는 대신, 각 주 이름을 주도와 주화(state flower)를 담고 있는 딕셔너리에 매핑하는 딕셔너리를 생성해보자.
>>> states = {
... "California": {
... "capital": "Sacramento",
... "flower": "California Poppy"
... },
... "New York": {
... "capital": "Albany",
... "flower": "Rose"
... },
... "Texas": {
... "capital": "Austin",
... "flower": "Bluebonnet"
... },
... }
다음과 같이 각 키의 값은 딕셔너리이다.
>>> states["Texas"]
{'capital': 'Austin', 'flower': 'Bluebonnet'}
텍사스의 주화를 다음과 같이 얻을 수 있다.
>>> states["Texas"]["flower"]
'Bluebonnet'