초보 개발자

16강 dict & defaultdict 본문

Python/윤성우 열혈 파이썬

16강 dict & defaultdict

taehyeki 2021. 12. 24. 12:54

[키가 존재할 때와 존재하지 않을 때]

d = {'red':3, 'white':2, 'blue':4}
d['red'] = 1 # 키 'red'의 값을 1로 변경
d
 {'red':3, 'white':2, 'blue':4}

여기선 d['red'] = 1 를 실행했을 때 이미 d안에 'red'라는 키값이 존재 하니까 그에 대당하는 값을 1로 바꾼다.

 

d = {'white':2, 'blue':4}
d['red'] = 1 # 키 'red' : 1추가
d
 {'white':2, 'blue':4, 'red':1 }

반대로 이와 같은 경우 d안에 'red'에 해당하는 키가 존재하지 않으니까 이번에는 새로운 키와 값의 추가로 이어진다.

 

그런데 저장되어 있는 값을 참조하는 경우에는 얘기가 좀 달라진다.

d = {'red':3,'white':2, 'blue':4}
d['red'] += 1 # 키 'red'의 값을 1증가
d
 {'red':4,'white':2, 'blue':4, 'red':1 }

이 경우 키와 그 값이 존재하니까 += 연산을 무리없이 처리한다. 

다음과 같이 해당키가 존재하지 않으면 예외가 발생한다.

d = {'white':2, 'blue':4}
d['red'] += 1 # 키 'red'의 값을 1증가
Traceback (most recent call last):
	.....

 

따라서 이런 유형의 예외가 발생할 수 밖에 없는 상황이라면 그에 따른 처리를 미리 해둘 필요가 있다.

즉 키가 존재할 때와 존재하지 않을 때의 상활 별 실행 코드를 구분할 필요가 있다.

s = 'robbot' # 일부러 b를 2개 넣음
d {}
for k in s:
	if k in d: # 키가 존재하면,
    	d[k] += 1 # 해당 키의 값을 1증가
    else: # 키가 존재하지 않으면,
    	d[k] = 1 # 해당 키의 값을 1로 해서 새로 추가
        
d # 문자 r이 하나 o가 둘..
{'r':1, 'o':2, 'b':2, 't':1}

 

[setdefault 메소드]

  그런데 이를 대신할 수 있는 방법 2가지를 소개하고자 한다.

 

첫 번째 방법은 setdefault 메소드를 사용하는 것이다. 이 메소드를 사용하면 앞서 보인 예제를 다음과 같이 간단힌 작성할 수 있다.

 

s = 'robbot' # 일부러 b를 2개 넣음
d {}
for k in s:
	d[k] = d.setdefault(k,0) + 1 # 딕셔너리의 setdefault 메소드 호출
    
d
{'r':1, 'o':2, 'b':2, 't':1}

setdefault메소드는 다음과 같이 동작한다.

d.setdefault(k,v)      # 매개변수k에는 키, v에는 디폴트 값 전달

-> k에 해당하는 키가 있을 때, 그 키의 값을 반환한다.

-> k에 해당하는 키가 없을 때, 딕셔너리에 k : v 저장하고 v를 반환한다.

 

즉 위 예제의 다음 문장에서는 덧셈 연산이 진행되는데, 이 덧셈을 위해서 setdefault 메소드가 먼저 호출된다.

d[k] = d.setdefault(k,0) + 1 # 먼저 setdefault 메소드가 호출된다.

 

따라서 k에 해당하는 키가 없다면키와 더불어 값이 0으로 저장된다. 

d[k]d.setdefault(k,0) + 1  # 이어서 덧셈 그리고 대입 연산이 진행된다.

 

그 키의 값이 1로 바뀐다. 물론 k에 해당하는 키가 있다면 그 값이 1증가하는 것으로 끝난다. 따라서 setdefault 메소드를 사용하면 if ~ else를 넣어서 복잡해질 수 있는 코드를 간결하게 구성할 수 있다.

 

 

[defaultdict]

또 다른 방법으로 '디폴트 값을 갖는 딕셔너리'를 생성하는 방법도 있다.

이 딕셔너리는 찾는 키가 없으면 예외를 발생시키지 않고 (기존의 dict에서는 예외 발생!! ) 해당키를 추가하되, 미리 등록해 놓은 함수가 반환하는 디폴트 값을 그 키의 값으로 저장한다. 잘 와닿지 않는다면 아래 예에서 확인해보자!!

from collections import defaultdict # default는 collcetions 모듈의 함수임
s = 'robbot'
d = defaultdict(int) # int 함수를 등록하면서 defaultdict 호출
for k in s:
	d[k] += 1 # 일반 딕셔너리와 사용법은 같다.
    
d
defaultdict(<class 'int'>, {'r':1, 'o':2, 'b':2, 't':,1})

저번에 namedtuple을 다뤄볼 때에도 from collections에서 가져왔었다.

namedtuple이 궁금하다면 아래를 참고하자!!

2021.12.22 - [Python/윤성우 열혈 파이썬] - 12강 네임드 튜플

 

12강 네임드 튜플

[네임드 튜플의 이해와 작성] tri_one = (12, 15) #삼각형 밑변 12와 높이 15를 묶어 놓은 것) tri_one (12, 15) 주석을 통해 앞에 있는 12가 밑변이고 15가 높이라고 말하지 않았다면 이 사실을 몰랐을 것이다

taehyeki.tistory.com

 

defaultdict은 예외가 발생하는 상황, 즉 어떤 키에 해당하는 값을 달라고 했을 경우 그 값이 없는 경우에 예외를 발생시키는 것이 아니라 디폴트 함수라고 이미 등록되어있는 함수를 호출한다(우리가 호출 X 딕셔너리가 호출 함). 그리고 그 함수가 반환하는 값을 키와 값으로 등록시킨다.

 

먼저 defaultdict을 쓰려면 collections 프레임 워크에서 import해와야한다. 그리고

d = defaultdict(int)

그리고 이렇게 메소드 호출을 통해서 딕셔너리를 만들어야 한다.

우리가 알고있던 딕셔너리 만드는 기존의 방법과는 다르다. 딕셔너리가 아닌 것 같아보이지만 이 것 또한 딕셔너리이다.

d = defaultdict(int)

여기서 int는 default method이다. 즉 default method로 int라는 함수를 등록하겠다라는 ~ 선언!

 

s = 'robbot'
for k in s:
	d[k] += 1

당연히 d['r']의 값은 처음에 없다. 그래서 int라는 함수를 호출한다. 근데 int라는 함수가 그냥 호출하면 0을 반환한다.!!

print(int())
0

따라서

A : d['r'] 가져와 ~ 

B : d['r'] 없는데요??

A : 그럼 디폴트 함수 실행시켜서 대충 ~그 값으로 만들어 가져오면 되잖아!!!

B :  (궁시렁.. 궁시렁..) int() = 0 -> d['r'] = 0 

즉 d['r'] 에는 0이라는 값이 들어왔다. 근데 여기서 끝나는 것이 아니라 += 1을 해주어야한다.

따라서 d['r'] = 0 + 1 이되어 1이라는 값이 들어오는 것이다.

그 이후 에 d['r']이 불리면 값이 존재하니 디폴드 함수를 실행시키지 않고 바로 값을 반환시켜준다.

 

from collections import defaultdict

def return_5():
    return 5
str = 'abcde'
dict = defaultdict(return_5)

for i in str:
    dict[i]


print(dict)
defaultdict(<function k at 0x000002106E6B3E20>, {'a': 5, 'b': 5, 'c': 5, 'd': 5, 'e': 5})
dict['None']
print(dict)
defaultdict(<function k at 0x000002106E6B3E20>, {'a': 5, 'b': 5, 'c': 5, 'd': 5, 'e': 5, 'None': 5})

 이렇게 값을 넣어주지 않고 키값만 넣어줘도 실행한다.

# 우리는 람다를 알고 있기 때문에 다음과 같이 defaultdict 함수를 호출할 수도 있다.
# 실제로 이런 상황에서는 람다식을 작성하는 것이 더 깔끔하다.

d = defaultdict(lambda:7) # 인자를 받지 않는 람다 7을 반환
d['z]

d
defaultdict(<function <lambda> at 0x000002AC1251C3A0>, {'z': 7})

 

지금까지 딕셔너리의 활용에 있어서 키가 없을 때 대처 방법 세가지를 소개 했다.

세가지 방법 모두 익혀보자!!