[Python] 12. dict & defaultdict & OrderedDict
본 포스팅은 “윤성우의 열혈 파이썬 중급편” 책 내용을 기반으로 작성되었습니다. 잘못된 내용이 있을 경우 지적해 주시면 감사드리겠습니다.
12-1. 키가 존재할 때와 존재하지 않을 때
- 딕셔너리에 키 존재 시 대입 연산 → 값의 수정
- 딕셔너리에 해당 키 존재하지 않을 시 대입 연산 → 새로운 키와 값의 추가
- 키 저장되어 있는 상태에서 값 참조하여 새로운 연산 수행 → 기존 값에 새로운 연산 수행
- 해당 키가 존재하지 않는 상태에서 값 참조 시도하여 새로운 연산 수행 → KeyError 예외 발생
키 존재할 때와 존재하지 않을 때 상황 별 실행코드 구분이 필요하다.
hi = 'hello'
d = {'h'=1}
for k in hi:
if k in d:
d[k] += 1 # 키 존재 시 값 참조하여 새로운 연산 수행
else:
d[k] = 1 # 키 존재 안하면 새로운 키와 값 추가
d
(결과) {'h': 1, 'e': 1, 'l': 2, 'o': 1}
12-2. setdefault 메소드
위 파이썬 코드를 구현하는데 꼭 if-else문을 써야할까?
한줄로 처리할 수 가 있다! 바로 setdefault 메소드로 말이다!
hi = 'hello'
d = {'h'=1}
for k in hi:
d[k] = d.setdefault(k, 0) + 1
d
(결과) {'h': 1, 'e': 1, 'l': 2, 'o': 1}
d[k] = d.setdefault(k, 0) + 1 는 다음과 같이 동작한다.
dictionary가 k를 키로 가지고 있음 → 키의 값을 반환하여 +1 연산 수행
dictionary가 k를 키로 가지고있지 않음 → dictionary에 k를 키로하고 default인 0을 값으로 갖는 요소 저장
12-3. defaultdict
위 파이썬 코드를 짧게 구현할 수 있는 또 다른 방법은 바로 defaultdict 함수를 호출하는 것이다. 바로 예제를 보자.
from collections import defaultdict
hi = 'hello'
d = defaultdict(int)
for k in hi:
d[k] += 1
d
(결과) defaultdict(<class 'int'>, {'h': 1, 'e': 1, 'l': 2, 'o': 1})
defaultdict는 default 값으로 int를 갖는다. 왜 int 인가?
int('36') # 문자열을 정수로 반환
int() # 아무값도 전달하지 않으면 0 반환
(결과) 36
0
바로 int()는 0을 반환하기 때문이다.
그런데 꼭 int를 default로 쓸 필요는 없다. 다른 녀석도 적용 가능하다!
from collections import defaultdict
def ret_zero():
return 0
d = defaultdict(ret_zero)
d['h']
d
(결과) defaultdict(<function ret_zero at 0x00000221037D1E18>, {'h': 0})
from collections import defaultdict
d = defaultdict(lambda: 7)
d['l']
d
(결과) defaultdict(<function <lambda> at 0x00000221037D1D90>, {'l': 7})
10-4. OrderedDict
파이썬 3.7 부터는 dictionary도 저장순서를 유지한다고 했다.
그런데 이전 버전은 어떻게 저장순서를 유지시킬 수 있었을까? 바로 OrderedDict를 쓰면 가능했다.
from collections import OrderedDict
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
for kv in od.items():
print(kv)
od
(결과) ('a', 1)
('b', 2)
('c', 3)
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
그럼 파이썬 3.7 이상을 쓰는 사람은 OrderedDict를 알 필요가 없는걸까?
다음 코드를 보자.
d1 = dict(a=1, b=2, c=3)
d2 = dict(c=3, a=1, b=2)
d1 == d2
(결과) True
나는 저장순서를 다르게 주어 d1과 d2를 구분하도록 하고 싶었다. 그런데 True라니… ㅠㅠ
이때 OrderedDict가 필요하다!
from collections import OrderedDict
od1 = OrderedDict(a=1, b=2, c=3)
od2 = OrderedDict(c=3, a=1, b=2)
od1 == od2
(결과) False
이처럼 dictionary의 저장순서에 의미를 부여하고 싶다면 OrderedDict를 쓰는게 좋다!
OrderedDict는 저장 순서를 맨 끝 또는 맨 앞으로 이동시키는 메소드도 갖는다.
from collections import OrderedDict
od = OrderedDict(a=1, b=2, c=3)
for kv in od.items():
print(kv, end=' ')
od.move_to_end('b') # 'b'와 그 값을 맨 뒤로 이동 시킴
for kv in od.items():
print(kv, end=' ')
od.move_to_end('b', last=False) # 'b'와 그 값을 맨 앞으로 이동 시킴
for kv in od.items():
print(kv, end=' ')
(결과) ('a', 1) ('b', 2) ('c', 3)
('a', 1) ('c', 3) ('b', 2)
('b', 2) ('a', 1) ('c', 3)
Leave a comment