15. 딕셔너리(Dictionary) 응용
1. 키워드
- 딕셔너리(Dictionary)
- 딕셔너리 표현식(Dictionary Comprehension)
2. 딕셔너리 응용하기
- 딕셔너리의 키-값 쌍을 조작하는 메서드와 정보를 조회하는 메서드를 사용해 보자.
3. 딕셔너리 조작하기
- 딕셔너리를 조작하는 메서드와 정보를 얻는 메서드부터 알아보자.
1) 딕셔너리에 키-값 쌍 추가하기
- 딕셔너리의 중요한 기능 중 하나가 바로 키-값 쌍 추가이다.
- 딕셔너리에 키-값 쌍을 추가하는 메서드는 다음과 같다.
1] setdefault
- 키-값 쌍 추가
2] update
- 키의 값 수정
- 키가 없으면 키-값 쌍 추가
2) 딕셔너리에 키와 기본값 저장하기
setdefault(키)
는 딕셔너리에 키-값 쌍을 추가한다.setdefault
에 키만 지정하면 값에None
을 저장한다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> x.setdefault("e")
>>> x
{'a': 10, 'b': 20, 'c': 30, 'd': 40, 'e': None}
setdefault(키, 기본값)
처럼 키와 기본값을 지정하면 값에 기본값을 저장한 뒤 해당 값을 반환한다.
3) 딕셔너리에서 키의 값 수정하기
update(키=값)
은 키의 값을 수정한다.- 예를 들어 딕셔너리가
x = {"a": 10}
이라면x.update(a=90)
과 같이 키에서 작은따옴표 또는 큰따옴표를 빼고 키 이름과 값을 지정한다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> x.update(a=90)
>>> x
{'a': 90, 'b': 20, 'c': 30, 'd': 40}
- 만약 딕셔너리에 키가 없으면 키-값 쌍을 추가한다.
- 딕셔너리
x
에는 키"e"
가 없으므로x.update(e=50)
을 실행하면"e": 50
을 추가한다.
update
는 키-값 쌍 여러 개를 콤마로 구분해서 넣어주면 값을 한꺼번에 수정할 수 있다.
update(키=값)
은 키가 문자열일 때만 사용할 수 있다.- 만약 키가 숫자일 경우에는
update(딕셔너리)
처럼 딕셔너리를 넣어서 값을 수정할 수 있다.
>>> y = {1: "one", 2: "two"}
>>> y.update({1: "ONE", 3: "THREE"})
>>> y
{1: 'ONE', 2: 'two', 3: 'THREE'}
- 다른 방법으로는 리스트와 튜플을 이용하는 방법도 있다.
update(리스트)
,update(튜플)
은 리스트와 튜플로 값을 수정한다.
- 특히
update(반복가능한객체)
는 키-값 쌍으로 된 반복 가능한 객체로 값을 수정한다. - 키 리스트와 값 리스트를 묶은
zip
객체로 값을 수정할 수 있다.
setdefault
와 update
의 차이
setdefault
는 키-값 쌍 추가만 할 수 있고, 이미 들어있는 키의 값은 수정할 수 없다.- 하지만
update
는 키-값 쌍 추가와 값 수정이 모두 가능하다.
4) 딕셔너리에서 키 값 쌍 삭제하기
pop(키)
는 딕셔너리에서 특정 키-값 쌍을 삭제한 뒤 삭제한 값을 반환한다.
pop(키, 기본값)
처럼 기본값을 지정하면 딕셔너리에 키가 있을 때는 해당 키-값 쌍을 삭제한 뒤 삭제한 값을 반환하지만 키가 없을 때는 기본값만 반환한다.
pop
대신del
로 특정 키-값 쌍을 삭제할 수도 있다.- 이때
[]
에 키를 지정하여del
을 사용한다.
5) 딕셔너리에서 임의의 키-값 쌍 삭제하기
popitem()
은 딕셔너리에서 임의의 키-값 쌍을 삭제한 뒤 삭제한 키-값 쌍을 튜플로 반환한다.- 파이썬 3.6 이상에서는 마지막 키-값 쌍을 삭제하며 3.5 이하에서는 임의의 키-값 쌍을 삭제한다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> x.popitem()
('d', 40)
>>> x
{'a': 10, 'b': 20, 'c': 30}
6) 딕셔너리의 모든 키-값 쌍을 삭제하기
clear()
는 딕셔너리의 모든 키-값 쌍을 삭제한다.
7) 딕셔너리에서 키의 값을 가져오기
get(키)
는 딕셔너리에서 특정 키의 값을 가져온다.
get(키, 기본값)
처럼 기본값을 지정하면 딕셔너리에 키가 있을 때는 해당 키의 값을 반환하지만 키가 없을 때는 기본값을 반환한다.
8) 딕셔너리에서 키-값 쌍을 모두 가져오기
- 딕셔너리는 키와 값을 가져오는 다양한 메서드를 제공한다.
1] items
- 키-값 쌍을 모두 가져옴
2] keys
- 키를 모두 가져옴
3] values
- 값을 모두 가져옴
- 다음과 같이
items()
는 딕셔너리의 키-값 쌍을 모두 가져온다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> x.items()
dict_items([('a', 10), ('b', 20), ('c', 30), ('d', 40)])
keys()
는 키를 모두 가져온다.
values()
는 값을 모두 가져온다.
9) 리스트와 튜플로 딕셔너리 만들기
- 이번에는 리스트(튜플)로 딕셔너리를 만들어보자.
dict.fromkeys(키리스트)
는 키 리스트로 딕셔너리를 생성하며 값은 모두None
으로 저장한다.
>>> keys = ["a", "b", "c", "d"]
>>> x = dict.fromkeys(keys)
>>> x
{'a': None, 'b': None, 'c': None, 'd': None}
dict.fromkeys(키리스트, 값)
처럼 키 리스트와 값을 지정하면 해당 값이 키의 값으로 저장된다.
defaultdict
사용하기
- 지금까지 사용한 딕셔너리(
dict
)는 없는 키에 접근했을 경우 에러가 발생한다.
- 에러가 발생하지 않게 하려면
defaultdict
를 사용한다. defaultdict
는 없는 키에 접근하더라도 에러가 발생하지 않으며 기본값을 반환한다.defaultdict
는collections
모듈에 들어있으며 기본값 생성 함수를 넣는다.
- 다음은 기본값이
0
인defaultdict
딕셔너리를 만든다.
- 딕셔너리
y
에는 키"z"
가 없지만y["z"]
와 같이 키의 값을 가져와보면0
이 나온다. - 왜냐하면 기본값을
0
으로 설정했기 때문이다.
defaultdict(int)
처럼int
를 넣었는데 기본값이0
인 이유는, int는 실수나 문자열을 정수로 변환하지만, 다음과 같이int
에 아무것도 넣지 않고 호출하면0
을 반환하기 때문이다.
defaultdict
에는 특정 값을 반환하는 함수를 넣어주면 되는데,defaultdict(int)
는 기본값 생성 함수로int
를 지정하여0
이 나오도록 만든 것이다.
- 만약
0
이 아닌 다른 값을 기본값으로 설정하고 싶다면 다음과 같이 기본값 생성 함수를 만들어서 넣어주면 된다.
- 여기서는 문자열
'python'
을 반환하는lambda: "python"
을 넣어서'python'
이 기본값이 되도록 설정했다.
4. 반복문으로 딕셔너리의 키-값 쌍을 모두 출력하기
- 이번에는 딕셔너리와
for
반복문을 사용하여 간단하게 모든 키-값 쌍을 출력해 보자.
for i in x:
처럼for
반복문에 딕셔너리를 지정한 뒤에print
로 변수i
를 출력해 보면 값은 출력되지 않고 키만 출력된다.
- 키와 값을 모두 출력하려면 다음과 같이
for in
뒤에 딕셔너리를 지정하고items
를 사용해야 한다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> for key, value in x.items():
... print(key, value)
...
a 10
b 20
c 30
d 40
for key, value in x.items():
는 딕셔너리x
에서 키-값 쌍을 꺼내서 키는key
에 값은value
에 저장하고, 꺼낼 때마다 코드를 반복한다.- 따라서
print
로key
와value
를 출력하면 키-값 쌍을 모두 출력할 수 있다.
- 물론 다음과 같이
in
다음에 딕셔너리를 직접 지정하고items
를 사용해도 상관없다.
1) 딕셔너리의 키만 출력하기
keys
로 키만 가져올 수 있다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> for key in x.keys():
... print(key, end=" ")
...
a b c d
2) 딕셔너리의 값만 출력하기
values
로 값만 가져올 수 있다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> for value in x.values():
... print(value, end=" ")
...
10 20 30 40
5. 딕셔너리 표현식 사용하기
- 리스트와 마찬가지로 딕셔너리도
for
반복문과if
조건문을 사용하여 딕셔너리를 생성할 수 있다.
>>> keys = ["a", "b", "c", "d"]
>>> x = {key: value for key, value in dict.fromkeys(keys).items()}
>>> x
{'a': None, 'b': None, 'c': None, 'd': None}
- 딕셔너리 표현식을 사용할 때는
for in
다음에 딕셔너리를 지정하고items
를 사용한다. - 그리고 키, 값을 가져온 뒤에는
키: 값
형식으로 변수나 값을 배치하여 딕셔너리를 생성하면 된다.
- 즉,
dict.fromkeys(keys).items()
로 키-값 쌍을 구한 뒤 키는 변수key
, 값은 변수value
에 꺼내고 최종적으로key
와value
를 이용하여 딕셔너리를 만든다.
- 물론 다음과 같이
keys
로 키만 가져온 뒤 특정 값을 넣거나,values
로 값을 가져온 뒤 값을 키로 사용할 수도 있다.
>>> {key: 0 for key in dict.fromkeys(["a", "b", "c", "d"]).keys()}
{'a': 0, 'b': 0, 'c': 0, 'd': 0}
>>> {value: 0 for value in {"a": 10, "b": 20, "c": 30, "d": 40}.values()}
{10: 0, 20: 0, 30: 0, 40: 0}
- 또는, 키와 값의 자리를 바꾸는 등 여러 가지로 응용할 수 있다.
>>> {value: key for key, value in {"a": 10, "b": 20, "c": 30, "d": 40}.items()}
{10: 'a', 20: 'b', 30: 'c', 40: 'd'}
1) 딕셔너리 표현식에서 if
조건문 사용하기
- 딕셔너리 표현식을 사용해 보면 복잡하기만 하고
dict.fromkeys
함수만 사용한 결과와 큰 차이점이 없다. - 대신 딕셔너리 표현식은 딕셔너리에서 특정 값을 찾아서 삭제할 때 유용하다.
x = {"a": 10, "b": 20, "c": 30, "d": 40}
for key, value in x.items():
if value == 20:
del x[key]
print(x) # RuntimeError: dictionary changed size during iteration
- 반복 도중에 딕셔너리의 크기가 바뀌었다는 에러가 발생한다.
- 즉, 딕셔너리는
for
반복문으로 반복하면서 키-값 쌍을 삭제하면 안 된다.
- 이때는 다음과 같이 딕셔너리 표현식에서
if
조건문을 사용하여 삭제할 값을 제외하면 된다.
>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}
>>> x = {key: value for key, value in x.items() if value != 20}
>>> x
{'a': 10, 'c': 30, 'd': 40}
- 딕셔너리 표현식에서
if value != 20
과 같이if
조건문을 지정하면 값이20
이 아닌 키-값 쌍으로 다시 딕셔너리를 만든다. - 직접 키-값 쌍을 삭제하는 방식이 아니라 삭제할 키-값 쌍을 제외하고 남은 키-값 쌍으로 딕셔너리를 새로 만드는 것이다.
6. 딕셔너리 안에서 딕셔너리 사용하기
- 이번에는 딕셔너리 안에서 딕셔너리를 사용하는 중첩 딕셔너리를 알아보자.
- 다음과 같이 딕셔너리는 값 부분에 다시 딕셔너리가 계속 들어갈 수 있다.
terrestrial_planet = {
"Mercury": {
"mean_radius": 2439.7,
"mass": 3.3022E+23,
"orbital_period": 87.969
},
"Venus": {
"mean_radius": 6051.8,
"mass": 4.8676E+24,
"orbital_period": 224.70069,
},
"Earth": {
"mean_radius": 6371.0,
"mass": 5.97219E+24,
"orbital_period": 365.25641,
},
"Mars": {
"mean_radius": 3389.5,
"mass": 6.4185E+23,
"orbital_period": 686.9600,
}
}
print(terrestrial_planet["Venus"]["mean_radius"]) # 6051.8
- 중첩 딕셔너리는 계층형 데이터를 저장할 때 유용하다.
- 딕셔너리 안에 들어있는 딕셔너리에 접근하려면 딕셔너리 뒤에
[]
(대괄호)를 단계만큼 붙이고 키를 지정해 주면 된다.
7. 딕셔너리의 할당과 복사
- 리스트와 마찬가지로 딕셔너리도 할당과 복사는 큰 차이점이 있다.
- 먼저 딕셔너리를 만든 뒤 다른 변수에 할당한다.
y = x
와 같이 딕셔너리를 다른 변수에 할당하면 딕셔너리는 두 개가 될 것 같지만 실제로는 딕셔너리가 한 개이다.
- 다음과 같이
x
와y
를is
연산자로 비교해 보면True
가 나오며, 이는 변수 이름만 다를 뿐 딕셔너리x
와y
는 같은 객체라는 것을 의미한다.
x
와y
는 같으므로y["a"] = 99
와 같이 키"a"
의 값을 변경하면 딕셔너리x
와y
에 모두 반영된다.
- 딕셔너리
x
와y
를 완전히 다른 두 개로 만들려면copy
메서드로 모든 키-값 쌍을 복사해야 한다.
- 이제
x
와y
를is
연산자로 비교해 보면False
가 나오며, 이는 두 딕셔너리가 다른 객체라는 것을 의미한다. - 하지만 복사한 키-값 쌍은 같으므로
==
로 비교하면True
가 나온다.
- 딕셔너리
x
와y
는 별개이므로 한쪽의 값을 변경해도 다른 딕셔너리에 영향을 미치지 않는다.
1) 중첩 딕셔너리의 할당과 복사 알아보기
- 다음과 같이 중첩 딕셔너리를 만든 뒤
copy
메서드로 복사한다.
- 이제
y["a"]["python"] = "2.7.15"
와 같이y
의 값을 변경해 보면x
와y
에 모두 반영된다.
>>> y["a"]["python"] = "2.7.15"
>>> x
{'a': {'python': '2.7.15'}, 'b': {'python': '3.6'}}
>>> y
{'a': {'python': '2.7.15'}, 'b': {'python': '3.6'}}
- 중첩 딕셔너리를 완전히 복사하려면
copy
메서드 대신copy
모듈의deepcopy
함수를 사용해야 한다.
>>> import copy
>>> x = {"a": {"python": "2.7"}, "b": {"python": "3.6"}}
>>> y = copy.deepcopy(x)
>>> y["a"]["python"] = "2.7.15"
>>> x
{'a': {'python': '2.7'}, 'b': {'python': '3.6'}}
>>> y
{'a': {'python': '2.7.15'}, 'b': {'python': '3.6'}}
- 이제 딕셔너리
y
의 값을 변경해도 딕셔너리x
에는 영향을 미치지 않는다. copy.deepcopy
함수는 중첩된 딕셔너리에 들어있는 모든 딕셔너리를 복사하는 깊은 복사를 해준다.