2 minute read

본 포스팅은 “윤성우의 열혈 파이썬 중급편” 책 내용을 기반으로 작성되었습니다. 잘못된 내용이 있을 경우 지적해 주시면 감사드리겠습니다.

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