Python에서 Defaultdict를 언제 어떻게 사용해야 합니까?

본 튜토리얼에서는 Python 딕셔너리(사전)를 다룰 때 발생하는 KeyError를 보다 효과적으로 처리하기 위해 Python의 collections 모듈에서 제공하는 defaultdict를 활용하는 방법을 설명합니다.

Python에서 딕셔너리는 키-값 쌍으로 데이터를 저장하는 강력한 내장 데이터 구조입니다. 키를 사용하여 딕셔너리에 접근하고 해당 값에 액세스할 수 있습니다.

그러나, Python 스크립트 실행 중에 수정되는 딕셔너리가 여러 개 있다면 KeyError가 자주 발생할 수 있습니다. 이러한 에러를 처리하는 다양한 방법이 있습니다.

본 튜토리얼에서는 다음과 같은 내용을 다룰 것입니다:

  • KeyError란 무엇이며 왜 발생하는가?
  • KeyError를 처리하는 방법
  • 누락된 키를 더 효율적으로 처리하기 위해 내장 dict 클래스를 상속받은 하위 클래스인 Python의 defaultdict를 사용하는 방법

시작해 보겠습니다!

Python에서 KeyError란 무엇인가?

Python 딕셔너리를 정의할 때 다음 사항을 유의해야 합니다.

  • 키는 중복 없이 고유해야 합니다.
  • 기존 반복 가능(iterable) 객체를 딕셔너리의 키로 사용할 때는 튜플과 같은 불변 컬렉션을 사용하는 것이 좋습니다.

따라서, 키는 딕셔너리 내에 존재해야만 유효합니다. 그렇지 않으면 KeyError가 발생합니다.

책 제목이 키이고 저자 이름이 값인 다음 딕셔너리 books_authors를 예시로 살펴보겠습니다.

Python REPL에서 이 튜토리얼과 함께 코딩해 볼 수 있습니다.

books_authors = {
    'Deep Work':'Cal Newport',
    'Hyperfocus':'Chris Bailey',
    'Pivot':'Jenny Blake',
    'The Happiness Equation':'Neil Pasricha'
}

키(책 제목)를 사용하여 저자 이름에 접근할 수 있습니다.

books_authors['Hyperfocus']
'Chris Bailey'

딕셔너리의 모든 키-값 쌍에 접근하려면, 딕셔너리 객체에서 items() 메서드를 호출하면 됩니다.

for book,author in books_authors.items():
  print(f"'{book}' by {author}")
'Deep Work' by Cal Newport
'Hyperfocus' by Chris Bailey
'Pivot' by Jenny Blake
'The Happiness Equation' by Neil Pasricha

딕셔너리에 없는 키 값에 접근하려고 하면, Python 인터프리터는 KeyError를 발생시킵니다. 존재하지 않는 키인 ‘Grit’ 및 ‘존재하지 않는 키’의 값에 접근하려고 시도하면 KeyError가 발생합니다.

books_authors['Grit']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-e1a4486f5ced> in <module>
----> 1 books_authors['Grit']

KeyError: 'Grit'
books_authors['non-existent-key']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-a3efd56f69e5> in <module>
----> 1 books_authors['non-existent-key']

KeyError: 'non-existent-key'

그렇다면 Python에서 KeyError는 어떻게 처리해야 할까요?

몇 가지 방법이 있으며, 다음 섹션에서 자세히 알아보겠습니다.

Python에서 KeyError를 처리하는 방법

다음과 같은 방법을 사용하여 KeyError를 처리하는 방법을 알아볼 것입니다.

  • If-else 조건문
  • Try-except 블록
  • 딕셔너리 메서드 .get()

#1. If-Else 조건문 사용

Python에서 KeyError를 처리하는 가장 간단한 방법 중 하나는 if-else 조건문을 사용하는 것입니다.

Python에서 if-else 문의 일반적인 구문은 다음과 같습니다.

 if condition:
 	# do this
 else:
    # do something else 
  • 조건이 True이면 if 블록 내의 명령문이 실행됩니다.
  • 조건이 False이면 else 블록 내의 명령문이 실행됩니다.

이 예에서는 조건이 딕셔너리에 키가 있는지 확인하는 것입니다.

키가 딕셔너리에 존재하면 in 연산자는 True를 반환하고 if 블록이 실행되어 해당 값을 출력합니다.

key = 'The Happiness Equation'
if key in books_authors:
  print(books_authors[key])
else:
  print('Sorry, this key does not exist!')

# Output
# Neil Pasricha

키가 딕셔너리에 없으면 in 연산자는 False를 반환하고 else 블록이 실행되어 키가 없다는 메시지를 출력합니다.

key = 'non-existent-key'
if key in books_authors:
  print(books_authors[key])
else:
  print('Sorry, this key does not exist!')

# Output
# Sorry, this key does not exist!

#2. Try-Except 문 사용

KeyError를 처리하는 또 다른 일반적인 방법은 Python에서 try-except 문을 사용하는 것입니다.

다음 코드 블록을 살펴보겠습니다.

key = 'non-existent-key'
try:
  print(books_authors[key])
except KeyError:
  print('Sorry, this key does not exist!')
  • try 블록은 제공된 키에 해당하는 값을 검색하려고 시도합니다.
  • 키가 없으면 인터프리터는 예외 블록 내에서 예외로 처리되는 KeyError를 발생시킵니다.

#3. .get() 메서드 사용

Python에서는 내장된 딕셔너리 메서드인 .get()을 사용하여 누락된 키를 처리할 수 있습니다.

get() 메서드를 사용하는 일반적인 구문은 dict.get(key,default_value)입니다. 여기서 dict는 Python에서 유효한 딕셔너리 객체입니다.

– 키가 딕셔너리에 있으면 get() 메서드가 값을 반환합니다.
– 그렇지 않으면 기본값을 반환합니다.

이 예에서는 액세스하려는 값의 키 목록이 있습니다. 키 목록을 반복하면서 books_authors 딕셔너리에서 해당하는 값을 검색합니다.

여기서는 ‘존재하지 않음’을 기본값으로 하여 .get() 메서드를 사용했습니다.

keys = ['Grit','Hyperfocus','Make Time','Deep Work']
for key in keys:
  print(books_authors.get(key,'Does not exist'))

위의 코드에서:

  • books_authors 딕셔너리에 있는 키의 경우 .get() 메서드는 해당 값을 반환합니다.
  • ‘Grit’ 및 ‘Make Time’ 키가 존재하지 않는 경우 .get() 메서드는 기본값인 ‘Does not exist’를 반환합니다.
# Output

Does not exist
Chris Bailey
Does not exist
Cal Newport

위에서 설명한 모든 방법은 KeyError를 처리하는 데 도움이 됩니다. 그러나 이러한 방법은 코드가 장황해지고 누락된 키를 명시적으로 처리해야 합니다. 일반 딕셔너리 대신 defaultdict를 사용하여 이 프로세스를 간소화할 수 있습니다.

파이썬의 Defaultdict

defaultdict는 딕셔너리(dict) 클래스의 하위 클래스입니다. 따라서 Python 딕셔너리의 동작을 상속합니다. 또한 기본적으로 누락된 키도 처리합니다.

defaultdict는 collections 모듈 내부에 있는 Python 표준 라이브러리의 컨테이너 데이터 유형입니다.

따라서 사용하기 전에 작업 환경으로 가져와야 합니다.

from collections import defaultdict

defaultdict를 사용하는 일반적인 구문은 다음과 같습니다.

defaultdict(default_factory)

int, float 또는 list와 같은 호출 가능한(callable) 객체를 default_factory 속성으로 지정할 수 있습니다. default_factory에 값을 제공하지 않으면 기본값은 None입니다.

찾고 있는 키가 없을 경우, __missing__() 메서드가 실행되어 default_factory에서 기본값을 추론합니다. 그런 다음 이 기본값을 반환합니다.

요약하자면:

  • Python에서 defaultdict는 키가 없을 때 기본값을 반환합니다.
  • 또한 이 키-기본값 쌍을 딕셔너리에 추가하여 수정할 수 있습니다.

Python Defaultdict 예제

다음으로, Python defaultdict가 어떻게 작동하는지 이해하기 위해 몇 가지 예제를 코딩해 보겠습니다.

기본 정수 값을 사용하는 Python의 Defaultdict

먼저 collections 모듈에서 defaultdict를 가져옵니다.

from collections import defaultdict
import random

defaultdict인 prices를 만들어 보겠습니다.

prices = defaultdict(int)

이제 과일 목록의 항목을 키로 사용하여 prices 딕셔너리를 채우고, price_list에서 값을 무작위로 샘플링하여 값을 얻습니다.

price_list = [10,23,12,19,5]
fruits = ['apple','strawberry','pomegranate','blueberry']

for fruit in fruits:
  prices[fruit] = random.choice(price_list)

prices defaultdict의 키-값 쌍을 살펴보겠습니다.

print(prices.items())
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10)])

일반 Python 딕셔너리와 마찬가지로, 키를 사용하여 prices defaultdict의 값에 접근할 수 있습니다.

prices['apple']
# 12

이제 존재하지 않는 과일, 예를 들어 ‘오렌지’의 가격에 접근해 봅시다. 기본값 0을 반환하는 것을 확인할 수 있습니다.

prices['orange']
# 0

딕셔너리를 출력하면, 기본 정수 값이 0인 새로운 키 ‘orange’가 추가된 것을 확인할 수 있습니다.

print(prices.items())
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10), ('orange', 0)])

List를 기본값으로 사용하는 Python의 Defaultdict

Students_majors를 리스트의 defaultdict로 정의해 보겠습니다. 전공 이름이 키이고, 값은 수학, 경제학, 컴퓨터 과학 등과 같은 각 전공을 공부하는 학생들의 목록입니다.

from collections import defaultdict
students_majors = defaultdict(list)

‘경제학’에 해당하는 학생 목록에 접근하려고 하면, defaultdict는 빈 목록을 반환합니다. KeyError가 발생하지 않습니다!

students_majors['Economics']
# []

이제 ‘경제학’ 전공에 매핑된 빈 목록이 있습니다. 이제 리스트 메서드 .append()를 사용하여 이 목록에 요소를 추가할 수 있습니다.

students_majors['Economics'].append('Alex')

students_majors defaultdict에 ‘경제학’에 대한 항목이 생성되었습니다.

print(students_majors)
defaultdict(<class 'list'>, {'Economics': ['Alex']})

경제학 전공에 매핑되는 리스트에 더 많은 학생을 추가하고, 새로운 전공을 추가하는 등의 작업을 할 수 있습니다!

students_majors['Economics'].append('Bob')
students_majors['Math'].append('Laura')
print(students_majors)
defaultdict(<class 'list'>, {'Economics': ['Alex', 'Bob'], 'Math': ['Laura']})

결론

이 튜토리얼이 Python에서 defaultdict를 언제 어떻게 사용해야 하는지 이해하는 데 도움이 되었기를 바랍니다. 이 튜토리얼의 코드 예제를 실행해 본 후, 필요할 때 defaultdict를 프로젝트의 기본 데이터 구조로 활용해 볼 수 있습니다.

다음은 이 튜토리얼에서 배운 내용을 요약한 것입니다.

  • Python 딕셔너리를 사용할 때 KeyError가 종종 발생합니다.
  • 이러한 KeyError를 처리하기 위해 몇 가지 장황한 방법을 사용할 수 있습니다. 조건문, try-except 블록 또는 .get() 메서드를 사용할 수 있습니다. 그러나 collections 모듈의 defaultdict 데이터 유형은 이러한 KeyError 처리를 단순화할 수 있습니다.
  • default_factory가 유효한 호출 가능한 객체인 경우 defaultdict(default_factory)를 사용할 수 있습니다.
  • defaultdict에 키가 없으면, 기본값(default_factory에서 추론)과 키가 defaultdict에 추가됩니다.

다음으로는 Python map 함수에 대한 튜토리얼을 확인해 보세요.