누가 투표를 했는지 저장하는 리스트 대신 카운터를 사용하는 최초 예제로 돌아가보자. 이 경우 왜 setdefault를 사용하지 않았을까? 다음은 같은 예제를 setdefault를 사용해 구현한 코드다.
count = counters.setdefault(key, 0) counters[key] = count + 1
여기서 문제점은 setdefault를 굳이 호출할 필요가 없다는 점이다. 카운터를 증가시키고 나면 그 값을 항상 딕셔너리에 저장해야 한다. 따라서 setdefault가 수행하는 디폴트 값 대입은 불필요하다. 처음에 본 get을 사용하는 접근 방법은 키가 없을 때 키를 한 번 읽고 한 번 대입해서 카운터를 증가시킬 수 있지만, setdefault를 사용하면 키를 한 번 읽고 대입을 두 번 수행한다.
setdefault를 사용하는 것이 딕셔너리 키를 처리하는 지름길인 경우는 드물다. 예를 들어 디폴트 값을 만들어내기 쉽거나, 디폴트 값이 변경 가능한 값이거나, 리스트 인스턴스처럼 값을 만들어낼 때 예외가 발생할 가능성이 없는 값인 경우 setdefault를 사용할 수 있다. 이런 구체적인 경우에는 get을 사용해 여러 줄로 로직을 기술하는 것보다 setdefault라는 혼동을 야기할 수 있는 이름을 받아들이는 편이 더 나아 보인다. 하지만 이런 상황에서도 실제로는 defaultdict를 사용하는 것으로 충분할 수도 있다(Better way 17: ‘내부 상태에서 원소가 없는 경우를 처리할 때는 setdefault보다 defaultdict를 사용하라’ 참고).
기억해야 할 내용
• 딕셔너리 키가 없는 경우를 처리하는 방법으로는 in 식을 사용하는 방법, KeyError 예외를 사용하는 방법, get 메서드를 사용하는 방법, setdefault 메서드를 사용하는 방법이 있다.
• 카운터와 같이 기본적인 타입의 값이 들어가는 딕셔너리를 다룰 때는 get 메서드가 가장 좋고, 딕셔너리에 넣을 값을 만드는 비용이 비싸거나 만드는 과정에 예외가 발생할 수 있는 경우에도 get 메서드를 사용하는 편이 더 낫다.
• 해결하려는 문제에 dict의 setdefault 메서드를 사용하는 방법이 가장 적합해 보인다면 setdefault 대신 defaultdict를 사용할지 고려해보라.