Skip to content

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(키, 기본값)처럼 키와 기본값을 지정하면 값에 기본값을 저장한 뒤 해당 값을 반환한다.


>>> x.setdefault("f", 100)
100

>>> x
{'a': 10, 'b': 20, 'c': 30, 'd': 40, 'e': None, 'f': 100}


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을 추가한다.


>>> x.update(e=50)

>>> x
{'a': 90, 'b': 20, 'c': 30, 'd': 40, 'e': 50}


  • update는 키-값 쌍 여러 개를 콤마로 구분해서 넣어주면 값을 한꺼번에 수정할 수 있다.


>>> x.update(a=900, f=60)

>>> x
{'a': 900, 'b': 20, 'c': 30, 'd': 40, 'e':50, 'f': 60}


  • update(키=값)은 키가 문자열일 때만 사용할 수 있다.
  • 만약 키가 숫자일 경우에는 update(딕셔너리)처럼 딕셔너리를 넣어서 값을 수정할 수 있다.


>>> y = {1: "one", 2: "two"}

>>> y.update({1: "ONE", 3: "THREE"})

>>> y
{1: 'ONE', 2: 'two', 3: 'THREE'}


  • 다른 방법으로는 리스트와 튜플을 이용하는 방법도 있다.
  • update(리스트), update(튜플)은 리스트와 튜플로 값을 수정한다.


>>> y.update([[2, "TWO"], [4, "FOUR"]])

>>> y
{1: 'ONE', 2: 'TWO', 3: 'THREE', 4: 'FOUR'}


  • 특히 update(반복가능한객체)는 키-값 쌍으로 된 반복 가능한 객체로 값을 수정한다.
  • 키 리스트와 값 리스트를 묶은 zip 객체로 값을 수정할 수 있다.


>>> y.update(zip([1, 2], ["one", "two"]))

>>> y
{1: 'one', 2: 'two', 3: 'THREE', 4: 'FOUR'}


setdefaultupdate의 차이

  • setdefault는 키-값 쌍 추가만 할 수 있고, 이미 들어있는 키의 값은 수정할 수 없다.
  • 하지만 update는 키-값 쌍 추가와 값 수정이 모두 가능하다.


>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}

>>> x.setdefault("a", 90)
10

>>> x
{'a': 10, 'b': 20, 'c': 30, 'd': 40}


4) 딕셔너리에서 키 값 쌍 삭제하기

  • pop(키)는 딕셔너리에서 특정 키-값 쌍을 삭제한 뒤 삭제한 값을 반환한다.


>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}

>>> x.pop("a")
10

>>> x
{'b': 20, 'c': 30, 'd': 40}


  • pop(키, 기본값)처럼 기본값을 지정하면 딕셔너리에 키가 있을 때는 해당 키-값 쌍을 삭제한 뒤 삭제한 값을 반환하지만 키가 없을 때는 기본값만 반환한다.


>>> x.pop("z", 0)
0


  • pop 대신 del로 특정 키-값 쌍을 삭제할 수도 있다.
  • 이때 []에 키를 지정하여 del을 사용한다.


>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}

>>> del x["a"]

>>> x
{'b': 20, 'c': 30, 'd': 40}


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()는 딕셔너리의 모든 키-값 쌍을 삭제한다.


>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}

>>> x.clear()

>>> x
{}


7) 딕셔너리에서 키의 값을 가져오기

  • get(키)는 딕셔너리에서 특정 키의 값을 가져온다.


>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}

>>> x.get("a")
10


  • get(키, 기본값)처럼 기본값을 지정하면 딕셔너리에 키가 있을 때는 해당 키의 값을 반환하지만 키가 없을 때는 기본값을 반환한다.


>>> x.get("z", 0)
0


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()는 키를 모두 가져온다.


>>> x.keys()
dict_keys(['a', 'b', 'c', 'd'])


  • values()는 값을 모두 가져온다.


>>> x.values()
dict_values([10, 20, 30, 40])


9) 리스트와 튜플로 딕셔너리 만들기

  • 이번에는 리스트(튜플)로 딕셔너리를 만들어보자.


  • dict.fromkeys(키리스트)는 키 리스트로 딕셔너리를 생성하며 값은 모두 None으로 저장한다.


>>> keys = ["a", "b", "c", "d"]

>>> x = dict.fromkeys(keys)

>>> x
{'a': None, 'b': None, 'c': None, 'd': None}


  • dict.fromkeys(키리스트, 값)처럼 키 리스트와 값을 지정하면 해당 값이 키의 값으로 저장된다.


>>> y = dict.fromkeys(keys, 100)

>>> y
{'a': 100, 'b': 100, 'c': 100, 'd': 100}


defaultdict 사용하기

  • 지금까지 사용한 딕셔너리(dict)는 없는 키에 접근했을 경우 에러가 발생한다.


>>> x = {"a": 0, "b": 0, "c": 0, "d": 0}

>>> x['z'] # KeyError: 'z'


  • 에러가 발생하지 않게 하려면 defaultdict를 사용한다.
  • defaultdict는 없는 키에 접근하더라도 에러가 발생하지 않으며 기본값을 반환한다.
  • defaultdictcollections 모듈에 들어있으며 기본값 생성 함수를 넣는다.


defaultdict(기본값생성함수)


  • 다음은 기본값이 0defaultdict 딕셔너리를 만든다.


>>> from collections import defaultdict

>>> y = defaultdict(int)


  • 딕셔너리 y에는 키 "z"가 없지만 y["z"]와 같이 키의 값을 가져와보면 0이 나온다.
  • 왜냐하면 기본값을 0으로 설정했기 때문이다.


>>> y["z"]
0


  • defaultdict(int)처럼 int를 넣었는데 기본값이 0인 이유는, int는 실수나 문자열을 정수로 변환하지만, 다음과 같이 int에 아무것도 넣지 않고 호출하면 0을 반환하기 때문이다.


>>> int()
0


  • defaultdict에는 특정 값을 반환하는 함수를 넣어주면 되는데, defaultdict(int)는 기본값 생성 함수로 int를 지정하여 0이 나오도록 만든 것이다.


  • 만약 0이 아닌 다른 값을 기본값으로 설정하고 싶다면 다음과 같이 기본값 생성 함수를 만들어서 넣어주면 된다.


>>> z = defaultdict(lambda: "python")

>>> z["a"]
'python'
>>> z[0]
'python'


  • 여기서는 문자열 'python'을 반환하는 lambda: "python"을 넣어서 'python'이 기본값이 되도록 설정했다.


4. 반복문으로 딕셔너리의 키-값 쌍을 모두 출력하기

  • 이번에는 딕셔너리와 for 반복문을 사용하여 간단하게 모든 키-값 쌍을 출력해 보자.


>>> x = {"a": 10, "b": 20, "c": 30, "d": 40}

>>> for i in x:
...     print(i, end=" ")
...
a b c d


  • 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에 저장하고, 꺼낼 때마다 코드를 반복한다.
  • 따라서 printkeyvalue를 출력하면 키-값 쌍을 모두 출력할 수 있다.


  • 물론 다음과 같이 in 다음에 딕셔너리를 직접 지정하고 items를 사용해도 상관없다.


for key, value in {"a": 10, "b": 20, "c": 30, "d": 40}.items():
    print(key, value)


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 조건문을 사용하여 딕셔너리를 생성할 수 있다.


{:  for ,  in 딕셔너리}
dict({:  for ,  in 딕셔너리})
>>> 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를 사용한다.
  • 그리고 키, 값을 가져온 뒤에는 키: 값 형식으로 변수나 값을 배치하여 딕셔너리를 생성하면 된다.


x = {key: value for key, value in dict.fromkeys(keys).items()}


  • 즉, dict.fromkeys(keys).items()로 키-값 쌍을 구한 뒤 키는 변수 key, 값은 변수 value에 꺼내고 최종적으로 keyvalue를 이용하여 딕셔너리를 만든다.


001


  • 물론 다음과 같이 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이 아닌 키-값 쌍으로 다시 딕셔너리를 만든다.
  • 직접 키-값 쌍을 삭제하는 방식이 아니라 삭제할 키-값 쌍을 제외하고 남은 키-값 쌍으로 딕셔너리를 새로 만드는 것이다.


002


6. 딕셔너리 안에서 딕셔너리 사용하기

  • 이번에는 딕셔너리 안에서 딕셔너리를 사용하는 중첩 딕셔너리를 알아보자.


  • 다음과 같이 딕셔너리는 값 부분에 다시 딕셔너리가 계속 들어갈 수 있다.


딕셔너리 = {키1: {키A: 값A}, 키2: {키B: 값B}}
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. 딕셔너리의 할당과 복사

  • 리스트와 마찬가지로 딕셔너리도 할당과 복사는 큰 차이점이 있다.


  • 먼저 딕셔너리를 만든 뒤 다른 변수에 할당한다.


>>> x = {"a": 0, "b": 0, "c": 0, "d": 0}

>>> y = x


  • y = x와 같이 딕셔너리를 다른 변수에 할당하면 딕셔너리는 두 개가 될 것 같지만 실제로는 딕셔너리가 한 개이다.


  • 다음과 같이 xyis 연산자로 비교해 보면 True가 나오며, 이는 변수 이름만 다를 뿐 딕셔너리 xy는 같은 객체라는 것을 의미한다.


>>> x is y
True


  • xy는 같으므로 y["a"] = 99와 같이 키 "a"의 값을 변경하면 딕셔너리 xy에 모두 반영된다.


>>> y["a"] = 99

>>> x
{'a': 99, 'b': 0, 'c': 0, 'd': 0}
>>> y
{'a': 99, 'b': 0, 'c': 0, 'd': 0}


  • 딕셔너리 xy를 완전히 다른 두 개로 만들려면 copy 메서드로 모든 키-값 쌍을 복사해야 한다.


>>> x = {"a": 0, "b": 0, "c": 0, "d": 0}

>>> y = x.copy()


  • 이제 xyis 연산자로 비교해 보면 False가 나오며, 이는 두 딕셔너리가 다른 객체라는 것을 의미한다.
  • 하지만 복사한 키-값 쌍은 같으므로 ==로 비교하면 True가 나온다.


>>> x is y
False

>>> x == y
True


  • 딕셔너리 xy는 별개이므로 한쪽의 값을 변경해도 다른 딕셔너리에 영향을 미치지 않는다.


>>> y["a"] = 99

>>> x
{'a': 0, 'b': 0, 'c': 0, 'd': 0}
>>> y
{'a': 99, 'b': 0, 'c': 0, 'd': 0}


1) 중첩 딕셔너리의 할당과 복사 알아보기

  • 다음과 같이 중첩 딕셔너리를 만든 뒤 copy 메서드로 복사한다.


>>> x = {"a": {"python": "2.7"}, "b": {"python": "3.6"}}

>>> y = x.copy()


  • 이제 y["a"]["python"] = "2.7.15"와 같이 y의 값을 변경해 보면 xy에 모두 반영된다.


>>> 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 함수는 중첩된 딕셔너리에 들어있는 모든 딕셔너리를 복사하는 깊은 복사를 해준다.

References