딕셔

딕셔너리 에서 Python

37개의 연습 문제

딕셔너리 소개

Python의 딕셔너리(dict)는 해시 가능한 _키_를 _값_에 연결하는 자료 구조로, 다른 프로그래밍 언어에서는 크기를 조절할 수 있는 해시 테이블, 해시맵, 또는 연관 배열이라고 불러요. 딕셔너리는 Python에 내장된 유일한 매핑 타입이에요.

keys는 해시 가능해야 하고 딕셔너리 전체에서 유일해야 해요. 키 타입으로는 number, str, 또는 (불변 값들로 이루어진) tuple 등이 올 수 있어요. list, dict, set처럼 가변 자료 구조는 키가 될 수 없어요. Python 3.7부터는 dict의 키 순서가 항목을 삽입한 순서대로 보장돼요.

values는 어떤 데이터 타입이나 구조든 될 수 있어요. 값은 얼마든지 중첩될 수 있어서, 배열의 배열, 하위 딕셔너리, 그 밖의 사용자 정의 또는 복합 자료 구조를 담을 수도 있어요.

key가 주어지면 딕셔너리는 (평균적으로) 상수 시간에 value를 가져올 수 있어요(항목 수와는 무관해요). index 위치를 모른 채 list나 array 안에서 값을 찾는 것과 비교하면, dict는 메모리를 훨씬 많이 쓰지만 값을 훨씬 빠르게 가져올 수 있어요.

딕셔너리는 항목이 많고 자주 접근하고 갱신해야 하는 상황에서 특히 유용해요.

딕셔너리 만들기

딕셔너리는 여러 가지 방법으로 만들 수 있어요.

  • fromkeys() 클래스 메서드 사용
  • 딕셔너리 컴프리헨션 사용
  • 언패킹(**)으로 두 딕셔너리 병합
  • |(update) 연산자로 딕셔너리 병합
  • 루프를 돌며 앞서 만든 빈 dict에 항목을 하나씩 추가

가장 간단한 두 가지 방법은 딕셔너리 _생성자_와 딕셔너리 _리터럴_이에요.

딕셔너리 생성자

dict()(dict 클래스의 생성자)는 key, value 쌍을 담은 반복 가능한 객체라면 무엇이든 사용할 수 있어요. <name>=<value> 형태의 인자 여러 개를 넘겨서 호출할 수도 있어요:

# Passing a list of key,value tuples.
>>> wombat = dict([('name', 'Wombat'),
...              ('speed', 23),
...              ('land_animal', True)])
{'name': 'Wombat', 'speed': 23, 'land_animal': True}


# Using key=value arguments.
>>> bear = dict(name="Black Bear",
...             speed=40,
...             land_animal=True)
{'name': 'Black Bear', 'speed': 40, 'land_animal': True}

dict에 관한 문서에 생성자 사용법의 다양한 변형과 옵션이 정리되어 있어요.

딕셔너리 리터럴

딕셔너리는 중괄호({})로 key : value 쌍을 감싸서 _딕셔너리 리터럴_로 직접 입력할 수도 있어요. {} 안에 들어가는 항목은 각각 다른 줄에 놓아도 돼요:

>>> whale = {"name": "Blue Whale", 
             "speed": 35, 
             "land_animal": False}
{'name': 'Blue Whale', 'speed': 35, 'land_animal': False}

>>> wombat = {'name': 'Wombat',
              'speed': 23,
              'land_animal': True,
              'color': 'Brindle'}

>>> wombat
{'name': 'Wombat', 'speed': 23, 'land_animal': True, 'color': 'Brindle'}

중첩 딕셔너리

딕셔너리는 얼마든지 중첩할 수 있어요:

animals = {
    "Real" : {
        "Winged" : {
            "Sparrow" : {'name': 'sparrow','speed': 12, 'land_animal': True},
            "Kestrel" : {'name': 'kestrel', 'speed': 15, 'land_animal': True}
           },
        "Legged" : {
            "Wombat" : {'name': 'Wombat', 'speed': 23, 'land_animal': True},
            "Black Bear": {'name': 'Black Bear', 'speed': 40, 'land_animal': True},
            "Polecat" : {'name': 'Polecat', 'speed': 15, 'land_animal': True}
           },
        "Other" :  {
            "Whale" : {'name': 'Blue Whale', 'speed': 35, 'land_animal': False},
            "Orca" : {'name': 'Orca', 'speed': 45, 'land_animal': False},
            "Snake" : {'name': 'Python', 'speed': 25, 'land_animal': True}
            }
        },
        
    "Imaginary": {
        "Winged" : {
            "Dragon" : {'name': 'Fire Dragon','speed': 100, 'land_animal': True},
            "Phoenix" : {'name': 'Phoenix', 'speed': 1500, 'land_animal': True}
            },
        "Legged" : {
            "Sphinx" : {'name': 'Sphinx','speed': 10, 'land_animal': True},
            "Minotaur" : {'name': 'Minotaur', 'speed': 5, 'land_animal': True}
            },
        "Other" :  {}
        }
   }

dict에서 값에 접근하기

대괄호 안에 _키_를 넣어 딕셔너리의 value에 접근할 수 있어요. 키가 딕셔너리에 없으면 KeyError가 발생해요:

>>> bear["speed"]
40

>>> bear["color"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'color'

get(<key>, <default value>) 메서드로 항목에 접근하면 KeyError를 피할 수 있어요:

>>> bear.get("color", 'not found')
'not found'

중첩 딕셔너리 항목에 접근하기

중첩 딕셔너리의 항목에 접근하려면 대괄호를 연달아 사용해요. 해당 키가 없으면 평소처럼 KeyError가 발생해요:

# Using the animals nested dictionary.
>>> animals["Real"]["winged"]["Kestrel"]["speed"]
15

>>> animals["Imaginary"]["winged"]["Kestrel"]["speed"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Kestrel'

KeyError를 피하려면 .get()을 쓸 수 있는데, .get() 호출은 반드시 _연결_해야 해요:

# Using the animals nested dictionary.
# Note the use of parenthesis to enable placing the 
# .get() calls on separate lines.
>>> (animals.get("Imaginary", {})
            .get("Legged", {})
            .get("Sphinx", {})
            .get("Color", "I have no idea!"))
'I have no idea!'

딕셔너리 값 바꾸기와 추가하기

항목의 value는 _키_에 값을 할당해서 바꿀 수 있어요:

# Assigning the value "Grizzly Bear" to the name key.
>>> bear["name"] = "Grizzly Bear"
{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True}

>>> whale["speed"] = 25
{'name': 'Blue Whale', 'speed': 25, 'land_animal': False}

새로운 key:value 쌍도 같은 방식으로 _추가_할 수 있어요:

# Adding a new "color" key with a new "tawney" value.
>>> bear["color"] = 'tawney'
{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True, 'color': 'tawney'}

>>> whale["blowholes"] = 1
{'name': 'Blue Whale', 'speed': 25, 'land_animal': False, 'blowholes': 1}

딕셔너리 항목 제거하기(pop과 del)

<dict>.pop(<key>) 메서드로 딕셔너리 항목을 삭제할 수 있어요. <dict>.pop()은 (key, value) 쌍을 제거하고 그 value를 반환해서 쓸 수 있게 해줘요. <dict>.get()처럼 <dict>.pop(<key>)도 두 번째 인자(<dict>.pop(<key>, <default value>))를 받을 수 있는데, 이 인자는 key를 찾지 못했을 때 반환돼요. 덕분에 KeyError가 발생하지 않아요:

# Using .pop() removes both the key and value, returning the value.
>>> bear.pop("name")
'Grizzly Bear'


# The "name" key is now removed from the dictionary.
# Attempting .pop() a second time will throw a KeyError.
>>> bear.pop("name")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'name'


# Using a default argument with .pop() will 
# prevent a KeyError from a missing key.
>>> bear.pop("name", "Unknown")
'Unknown'

del 문으로 항목을 하나 이상 제거할 수도 있어요. 제거하려는 항목이 딕셔너리에 없으면 KeyError가 발생해요:

>>> wombat = {'name': 'Wombat',
              'speed': 23,
              'land_animal': True,
              'color': 'Brindle',
              'talent': 'Singing',
              'size': 'small'}

# Remove a single entry from the dictionary.
>>> del wombat["color"]
>>> wombat
{'name': 'Wombat', 'speed': 23, 'land_animal': True, 'talent': 'Singing', 'size': 'small'}


# Remove multiple entries from the dictionary.
>>> del wombat["talent"], wombat["size"]
>>> wombat
{'name': 'Wombat', 'speed': 23, 'land_animal': True}


# Attempting a deletion of a non-existent key raises a KeyError
>>> del wombat["number_of_legs"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'number_of_legs'

딕셔너리 순회하기

for item in dict나 while item으로 딕셔너리를 순회하면 기본적으로 _키_를 대상으로 반복해요. 같은 루프 안에서 _대괄호_를 사용하면 _값_에도 접근할 수 있어요:

>>> for key in bear:
...     print((key, bear[key])) # <--This prints a tuple of (key, value).
('name', 'Black Bear')
('speed', 40)
('land_animal', True)

(key, value) 튜플을 반환하는 .items() 메서드를 쓸 수도 있어요:

# dict.items() forms (key, value tuples) that can be 
# unpacked and iterated over.
>>> for key, value in whale.items():
...     print(key, ":", value)
name : Blue Whale
speed : 25
land_animal : False
blowholes : 1

마찬가지로 .keys()는 keys를, .values()는 values를 반환해요.

Python 딕셔너리에 대한 자세한 설명은 공식 문서가 훌륭한 출발점이에요. W3-Schools 튜토리얼을 참고해도 좋아요.

딕셔너리 기능 확장하기: Collections 모듈

collections 모듈은 Python의 표준 컬렉션 기반 데이터 타입(dict, set, list, tuple)에 특화된 기능을 더해줘요. 가장 유용한 딕셔너리 기반 클래스 세 가지는 이래요:

  • Counter는 항목을 자동으로 세고, 항목을 키로, 그 개수를 값으로 하는 dict로 돌려줘요.
  • OrderedDict는 딕셔너리 항목의 순서를 다루는 데 특화된 메서드를 가지고 있어요.
  • defaultdict는 딕셔너리 항목을 가져오거나 대입할 때 key를 찾지 못하면 기본값을 설정하는 팩토리 메서드를 사용해요.
GitHub에서 편집 링크가 새 창이나 탭에서 열려요

딕셔너리 배우기

연습이 잠겨 있어요

딕셔너리 개념을 연습하려면 연습 문제 4개를 더 잠금 해제해요