파이썬 컨테이너 자료형 중 마지막인 딕셔너리에 대해 알아보겠습니다. 지금까지 배운 컨테이너들은 객체들이 나열되어 있는 형태였습니다. 사전 자료형은 두 객체가 키와 값으로 짝지어져서 나열되어 있는 형태입니다.
예를 들어 네이버 사전에서 "열대야"를 검색하면 방 밖의 온도가 25℃ 이상인 무더운 밤. 이라는 설명이 나옵니다. 이때 열대야가 검색 "키(key)" 역할을 하며 찾아낸 설명이 "값(value)"입니다.
리스트나 튜플이 시퀀스로 분류가 되듯이 사전은 '매핑(mapping)' 자료형으로 분류됩니다. 여기서 매핑은 지도가 아니라 일대일대응 같은 수학의 '사상'을 의미합니다. 현재 파이썬에는 매핑으로 분류되는 기본 자료형은 사전 한 가지뿐입니다.
수학적 의미에는 신경 쓰지 않으셔도 되지만 파이썬 프로그래밍 전반에 걸쳐 편리하게 사용되며 코딩 테스트에서 복잡한 알고리즘의 구현 난이도를 낮춰주는 중요한 컨테이너이기 때문에 잘 알아두셔야 합니다.
앞에서 배운 집합(set)과 비슷하게 키(key)에 대해서는 중복을 허용하지 않습니다. 파이썬 3.6부터 키(key)에 대해 순서유지(order preserving)가 추가되었습니다. 여기서는 3.6 이상을 기준으로 설명합니다.
사전(Dictionary)
이름 | type | 예시 | 가변성 | 순서유지 | 중복허용 |
---|---|---|---|---|---|
리스트 | list | ["사과", 123, 3.14] |
가변 | O | O |
튜플 | tuple | ("사과", 123, 3.14) |
불변 | O | O |
집합 | set | {"사과", 123, 3.14} |
가변 | X | X |
사전 | dict | {"원주율":3.14, 123:"일이삼"} |
가변 | 3.6+ | 키X값O |
사전(Dict)을 만드는 방법
중괄호(물결괄호{}
)와 컴마(,
)를 사용하는데 이때 키(key)와 값(value)을 콜론(:
)을 이용해서 짝을 지어줍니다. 코드 스타일링은 포매터에게 맡기는 게 편합니다.
d = {} # 비어있는 중괄호는 집합이 아니라 사전입니다. 집합을 생성하려면 d = set()을 사용해야 합니다.
d = dict() d = {
"바나나": "외떡잎식물 생강목 파초과 바나나 속에 속하는 식물의 총칭.",
"아이언맨": "여심을 사로잡는 매력적인 미소의 백만장자 플레이보이 토니 스타크(Tony Stark).",
123: 456, # 마지막 컴마는 무시합니다. 새로 아이템을 추가할 일이 많다면 남겨두는 게 편합니다.
}
더 다양한 방식으로 dict를 만들 수 있습니다.
# 모두 같은 dict를 만듭니다.
d1 = {"one": 1, "two": 2, "three": 3}
d2 = dict({"three": 3, "one": 1, "two": 2})
d3 = dict({"one": 1, "three": 3}, two=2)
d4 = dict(one=1, two=2, three=3)
print(id(1), d1)
print(id(2), d2)
print(id(3), d3)
print(id(4), d4)
2858377832752 {'one': 1, 'two': 2, 'three': 3}
2858377832784 {'three': 3, 'one': 1, 'two': 2}
2858377832816 {'one': 1, 'three': 3, 'two': 2}
2858377832848 {'one': 1, 'two': 2, 'three': 3}
모두 같은 dict를 만든다는 것은 키(key)에 대한 값(values)을 갖는다는 뜻입니다.
하지만 순서가 다르기에 id값이 서로 다르다는 것을 확인할 수 있습니다.
# 튜플의 리스트로도 dict를 생성할 수 있습니다.
d5 = dict([("two", 2), ("one", 1), ("three", 3)])
d5
{'two': 2, 'one': 1, 'three': 3}
# 튜플의 튜플로도 dict를 생성할 수 있습니다.
d_5 = dict((("two", 2), ("one", 1), ("three", 3)))
d_5
{'two': 2, 'one': 1, 'three': 3}
# 그럼 리스트의 튜플로도 dict를 생성할 수 있을까요?
d__5 = dict((["two", 2], ["one", 1], ["three", 3]))
d__5
{'two': 2, 'one': 1, 'three': 3}
# zip의 기능을 추측해보세요.
d6 = dict(zip(["one", "two", "three"], [1, 2, 3]))
d6
{'one': 1, 'two': 2, 'three': 3}
여기서 zip은 서로 다른 두 리스트로부터 아이템들을 하나씩 순서대로 가져와서 튜플로 묶어줍니다.
예를 들면 "one"과 1을 묶어서 ("one", 1)로 만들고 그다음에는 "two"와 2를 묶어서 ("two", 2)를 만듭니다.
zip의 결과를 (dict가 아니라) list로 만들면 튜플의 list가 됩니다.
# zip의 결과를 리스트로 만들면 튜플의 리스트가 됩니다.
list(zip(["one", "two", "three"], [1, 2, 3]))
[('one', 1), ('two', 2), ('three', 3)]
키가 중복될 경우에는 마지막 하나만 남습니다. 집합에서 아이템의 중복을 허용하지 않은 것과 비슷합니다.
# 키가 중복될 경우 마지막이 남습니다.
my_dict = {"위스키": "Captain","위스키": "한잔",}
my_dict
{'위스키': '한잔'}
값의 중복은 가능합니다.
my_dict = {"사과":"맛있어", "수박":"맛있어"}
my_dict
{'사과': '맛있어', '수박': '맛있어'}
키에는 불변 객체만 사용할 수 있습니다. 키가 변경되면 찾을 수가 없기 때문입니다. 리스트 같은 가변 객체에서 의도치 않게 아이템이 변경되는 경우는 리스트에서 다루었습니다.
# 튜플을 키로 사용 가능합니다.
my_dict = {("사과", "수박"): "맛있어"}
my_dict
{('사과', '수박'): '맛있어'}
my_dict[("사과", "수박")]
'맛있어'
# 리스트를 키로 사용 불가능합니다. 리스트는 가변객체이기 때문입니다.
my_dict = {["사과", "수박"]: "맛있어"}
my_dict
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [17], in <cell line: 2>()
1 # 리스트를 키로 사용 불가능합니다. 리스트는 가변객체이기 때문입니다.
----> 2 my_dict = {["사과", "수박"]: "맛있어"}
3 my_dict
TypeError: unhashable type: 'list'
# 값에 리스트를 사용하는 것은 가능
my_dict = {"컨테이너":["list", "tuple", "set", "dictionary"]}
my_dict
{'컨테이너': ['list', 'tuple', 'set', 'dictionary']}
my_dict["컨테이너"]
['list', 'tuple', 'set', 'dictionary']
사전(dict)의 사용 방법
대괄호(bracket) 안에 키(key)를 넣어서 값(value)을 찾을 수 있습니다.
d = { "A": 65,"B": 66,"C": 67,}
d["A"]
65
키에 문자열을 사용할 경우 당연히 대소문자를 구분합니다. 키를 찾지 못할 경우 에러가 발생합니다.
d["b"]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Input In [26], in <cell line: 1>()
----> 1 d["b"]
KeyError: 'b'
만약 사전에 들어있는지 아닌지 예상할 수 없는 키에 대해서 사전을 찾아봐야 할 일이 있다면get()
메써드를 사용할 수 있습니다. 키가 존재하지 않을 경우에는 에러를 발생시키는 대신에None
을 줍니다.
d = {"A": 65, "B": 66, "C": 67,}
print(d.get("A"))
65
d.get("A")
65
d = {"A": 65, "B": 66, "C": 67,}
# get()을 이용해서 존재하지 않는 key에 대한 value를 요청하면
# 에러 없이 None을 줍니다.
print(d.get("b"))
None
d.get("b")
# if문과 함께 사용해서 키가 존재하지 않는 경우에 대응
d = {"A": 65, "B": 66, "C": 67,}
v = d.get(input("키값을 입력하세요"))
if v == None:
print("The key doesn't exist in the dict.")
else:
print("The value is", v)
키값을 입력하세요A
The value is 65
# if문과 함께 사용해서 키가 존재하지 않는 경우에 대응
d = {"A": 65, "B": 66, "C": 67,}
v = d.get(input("키값을 입력하세요"))
if v == None:
print("The key doesn't exist in the dict.")
else:
print("The value is", v)
키값을 입력하세요a
The key doesn't exist in the dict.
# 키가 존재하지 않는 경우 기본값을 반환하도록 설정 가능
d.get("b", "키가 존재하지 않아요.")
'키가 존재하지 않아요.'
# 멤버쉽 연산자를 사용해서 에러를 피하는 방법도 있어요.
if "b" in d:
print("The value is", d["b"])
else:
print("The key doesn't exist in the dict.")
The key doesn't exist in the dict.
# 멤버쉽 연산자를 사용해서 에러를 피하는 방법도 있어요.
my_key = input("키값을 입력하세요: ")
if my_key in d:
print("The value is", d[my_key])
else:
print("The key doesn't exist in the dict.")
키값을 입력하세요: C
The value is 67
# 멤버쉽 연산자를 사용해서 에러를 피하는 방법도 있어요.
my_key = input("키값을 입력하세요: ")
if my_key in d:
print("The value is", d[my_key])
else:
print("The key doesn't exist in the dict.")
키값을 입력하세요: b
The key doesn't exist in the dict.
현재 존재하지 않는 키라도 새로운 키:값 쌍을 새로 만들어서 넣을 수는 있습니다.
d["a"] = 100 # 넣은 순서가 유지됩니다.
d
{'A': 65, 'B': 66, 'C': 67, 'a': 100}
키에 float를 사용하는 것은 권장하지 않습니다.
# 1과 1.0을 구분하지 않습니다.
d = {1: "일", 1.0: "일점영"}
d
{1: '일점영'}
# 정밀도 문제로 키를 찾지 못할 수도 있습니다.
d = {0.1 * 0.1: "일일일일"}
d[0.01]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
Input In [39], in <cell line: 3>()
1 # 정밀도 문제로 키를 찾지 못할 수도 있습니다.
2 d = {0.1 * 0.1: "일일일일"}
----> 3 d[0.01]
KeyError: 0.01
불변 컨테이너를 키로 사용할 수 있습니다.
# 튜플을 키로 사용할 경우 괄호 생략 가능합니다.
my_dict = {("사과", "수박"): ["맛있어", "시원해"]}
my_dict
{('사과', '수박'): ['맛있어', '시원해']}
my_dict = {("사과", "수박"): ["맛있어", "시원해"]}
my_dict["사과", "수박"]
['맛있어', '시원해']
my_dict = {("사과", "수박"): ["맛있어", "시원해"]}
my_dict["사과", "수박"] = "쥬시콜"
my_dict
{('사과', '수박'): '쥬시콜'}
stock = {"apple": 0}
stock["apple"] += 1
stock["apple"] = stock["apple"] + 10
stock["apple"]
11
d = {"어벤져스": ["블랙위도우", "호크아이"]}
d = {"어벤져스": ["블랙위도우", "호크아이"]}
d["어벤져스"] = ("캡틴아메리카", "앤트맨", "마동석")
d
{'어벤져스': ('캡틴아메리카', '앤트맨', '마동석')}
# 값이 시퀀스일 경우 인덱싱/슬라이싱 가능
d["어벤져스"][2]
'마동석'
d["어벤져스"][::-1]
('마동석', '앤트맨', '캡틴아메리카')
d["어벤져스"][0:2]
('캡틴아메리카', '앤트맨')
d = {"어벤져스": ["블랙위도우", "호크아이", "마동석"]}
d["어벤져스"].append("아이언맨")
d
{'어벤져스': ['블랙위도우', '호크아이', '마동석', '아이언맨']}
d["어벤져스"].reverse()
d
{'어벤져스': ['아이언맨', '마동석', '호크아이', '블랙위도우']}
dict안에 dict를 값으로 넣을 수 있습니다.
d = {"key1": {"key2": {"key3": "value"}}}
d["key1"]["key2"]["key3"]
'value'
del
키워드를 이용해서 키:값 쌍을 삭제할 수 있습니다. pop()
과는 달리 삭제된 값을 다시 변수에 넣을 수는 없고 그냥 삭제만 합니다.
my_dict = {"A": 65, "B": 66, "C": 67, "D": 68}
del my_dict["A"]
my_dict
{'B': 66, 'C': 67, 'D': 68}
# pop()도 사용가능합니다. list와 달리 인덱스가 아니라 키를 넣어줘야 합니다.
my_dict = {"A": 65, "B": 66, "C": 67, "D": 68}
my_dict = {"A": 65, "B": 66, "C": 67, "D": 68}
print(my_dict.pop("A"))
print(my_dict)
65
{'B': 66, 'C': 67, 'D': 68}
my_dict
{'B': 66, 'C': 67, 'D': 68}
# 모두 지우고 싶을 때는 clear()도 사용할 수 있습니다.
my_dict.clear()
my_dict
{}
리스트에도 del
을 사용할 수 있습니다.
#인덱스를 이용해 지울 수 있습니다.
my_list = ["A", "B", "C", "D", "E"]
del my_list[4]
my_list
['A', 'B', 'C', 'D']
# 슬라이싱을 이용해 지울 수도 있습니다.
my_list = ["A", "B", "C", "D", "E"]
del my_list[2:4]
my_list
['A', 'B', 'E']
del
로 아예 변수를 지워버릴 수도 있습니다.
# 변수가 삭제되어 정의되지 않았다는 오류메시지를 볼 수 있습니다.
to_be_deleted = {"A": 65, "B": 66, "C": 67, "D": 68}
del to_be_deleted
to_be_deleted
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [62], in <cell line: 5>()
1 to_be_deleted = {"A": 65, "B": 66, "C": 67, "D": 68}
3 del to_be_deleted
----> 5 to_be_deleted
NameError: name 'to_be_deleted' is not defined
del
로 변수를 삭제하는 것은 부득이한 경우에만 사용해야 합니다.
지워야 할 변수라면 애초에 영역을 제한하는 것이 좋습니다.
사전의 아이템은 키와 값의 쌍이라는 점에서 다른 컨테이너들과 용법이 약간 다릅니다.
# dict를 list로 바꾸면 key만 남습니다.
alphabets = {"A": 65, "B": 66, "C": 67, "D": 68}
list(alphabets)
['A', 'B', 'C', 'D']
len()
과 in
도 키(key)를 기준으로 작동합니다.
len(alphabets)
4
65 in alphabets
False
"A" in alphabets
True
keys()
메써드와 values()
메써드를 이용해서 각각 키와 값의 리스트를 만들 수 있습니다.
alphabets.keys()
dict_keys(['A', 'B', 'C', 'D'])
type(alphabets.keys())
dict_keys
list(alphabets.keys())
['A', 'B', 'C', 'D']
list(alphabets.values())
[65, 66, 67, 68]
[참고] 키 리스트와 값 리스트를 zip으로 묶으면 다시 원래 dict가 됩니다.
alphabets = {"A": 65, "B": 66, "C": 67, "D": 68}
key_list = list(alphabets.keys())
value_list = list(alphabets.values())
print(dict(zip(key_list, value_list)))
{'A': 65, 'B': 66, 'C': 67, 'D': 68}
alphabets = {"A": 65, "B": 66, "C": 67, "D": 68}
key_list = list(alphabets.keys())
value_list = list(alphabets.values())
print(tuple(zip(key_list, value_list)))
(('A', 65), ('B', 66), ('C', 67), ('D', 68))
alphabets = {"A": 65, "B": 66, "C": 67, "D": 68}
key_list = list(alphabets.keys())
value_list = list(alphabets.values())
print(list(zip(key_list, value_list)))
[('A', 65), ('B', 66), ('C', 67), ('D', 68)]
items()
메써드를 이용해서 (키, 값)
튜플의 리스트를 만들 수 있습니다.
list(alphabets.items())
[('A', 65), ('B', 66), ('C', 67), ('D', 68)]
items()
는 반복문과 함께 사용하기 편합니다.
for my_items in alphabets.items():
print(my_items)
('A', 65)
('B', 66)
('C', 67)
('D', 68)
for key, value in alphabets.items():
print(f"Key: {key}, Value: {value}")
Key: A, Value: 65
Key: B, Value: 66
Key: C, Value: 67
Key: D, Value: 68
# 만약 정렬된 순서로 iterate하고 싶다면 sorted()를 사용할 수 있습니다.
alphabets = {"E": "East", "A": 65, "B": 70, "C": 75, "D": 80}
for k in sorted(alphabets):
print(f"{k} => {alphabets[k]}")
A => 65
B => 70
C => 75
D => 80
E => East
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
'수학과 코딩' 카테고리의 다른 글
파이썬(python) 조건문(if.elif, else) 사용 방법 정리 (0) | 2022.07.29 |
---|---|
파이썬(python) 표현식과 문장의 뜻 불리언(boolean) 자료형 (0) | 2022.07.28 |
파이썬(python)컨테이너(container) 집합(set) 사용법 및 특징 (0) | 2022.07.27 |
파이썬(python) 튜플(tuple)과 시퀀스(sequense) 정리 (0) | 2022.07.27 |
파이썬(python) 리스트의 사용 방법 총 정리(매소드, 중첩리스트, 반복문) (0) | 2022.07.26 |
댓글