Collections 모듈의 확장 자료구조
defaultdict - 기본값이 있는 딕셔너리
존재하지 않는 키에 접근할 때 KeyError를 발생시키는 대신, 자동으로 지정한 기본값으로 초기화해주는 딕셔너리이다.
데이터 그룹화나 개수 세기 같은 작업에서 조건문 없이 간결한 코드를 작성할 수 있고, 중첩 딕셔너리를 생성할 때 유용하게 사용할 수 있다.
기본 사용법
from collections import defaultdict
intdd = defaultdict(int) # 0으로 초기화
listdd = defaultdict(list) # []로 초기화
setdd = defaultdict(set) # {}로 초기화
intdd["key"]
listdd["key"]
setdd["key"]
print(intdd) # defaultdict(<class 'int'>, {'key': 0})
print(listdd) # defaultdict(<class 'list'>, {'key': []})
print(setdd) # defaultdict(<class 'set'>, {'key': set()})
defaultdict 활용 word count 예제
from collections import defaultdict
# 일반 딕셔너리로 단어 개수 세기
normal_dict = {}
text = "apple banana apple orange"
for word in text.split():
if word in normal_dict: # 키 존재 여부 확인 필요
normal_dict[word] += 1
else:
normal_dict[word] = 1
# defaultdict로 단어 개수 세기 - 더 간결함
word_count = defaultdict(int) # 기본값으로 0을 반환하는 int 함수 지정
for word in text.split():
word_count[word] += 1 # 키가 없어도 자동으로 0으로 초기화
print(dict(word_count)) # {'apple': 2, 'banana': 1, 'orange': 1}
Counter - 요소 개수 세기
객체의 개수를 세는 데 특화된 딕셔너리이다. 빈도 분석, 가장 흔한 요소 찾기, 카운터 간 수학적 연산이 가능하다.
기본 사용법
from collections import Counter
# 텍스트에서 문자 빈도 계산
c = Counter("mississippi")
print(c) # Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
# 가장 흔한 요소 찾기
print(c.most_common(2)) # [('i', 4), ('s', 4)]
# 다양한 초기화 방법
print(Counter(['a', 'b', 'a'])) # Counter({'a': 2, 'b': 1})
print(Counter({'a': 3, 'b': 2})) # Counter({'a': 3, 'b': 2})
print(Counter(a=3, b=2)) # Counter({'a': 3, 'b': 2})
# 카운터 간 산술 연산
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2) # Counter({'a': 4, 'b': 3}) - 합집합
print(c1 - c2) # Counter({'a': 2}) - 차집합 (음수는 제외)
deque - 양방향 큐
양쪽 끝에서 빠르게 요소를 추가하고 제거할 수 있는 리스트 기반 컬렉션이다. 일반 리스트보다 삽입/삭제 연산이 효율적(O(1) 연산)이다. 큐, 스택, 슬라이딩 윈도우 등의 구현에 적합하다.
from collections import deque
# deque 생성
d = deque([1, 2, 3])
print(d) # deque([1, 2, 3])
# 양쪽 끝에 요소 추가
d.append(4) # 오른쪽 끝에 추가
d.appendleft(0) # 왼쪽 끝에 추가
print(d) # deque([0, 1, 2, 3, 4])
# 양쪽 끝에서 요소 제거
right = d.pop() # 오른쪽 끝에서 제거
left = d.popleft() # 왼쪽 끝에서 제거
print(d) # deque([1, 2, 3])
# 회전시키기
d.rotate(1) # 음수면 왼쪽으로 회전
print(d) # deque([3, 1, 2])
# 최대 길이 제한 (슬라이딩 윈도우 구현에 유용)
limited_deque = deque(maxlen=3)
for i in range(5):
limited_deque.append(i)
print(limited_deque)
# deque([0], maxlen=3)
# deque([0, 1], maxlen=3)
# deque([0, 1, 2], maxlen=3)
# deque([1, 2, 3], maxlen=3) - 가장 오래된 항목(0)이 자동으로 제거됨
# deque([2, 3, 4], maxlen=3) - 가장 오래된 항목(1)이 자동으로 제거됨
namedtuple - 키와 인덱스가 있는 튜플
인덱스뿐만 아니라 필드 이름으로도 접근할 수 있는 튜플의 확장형이다. 가벼운 클래스 대용으로 사용할 수 있으며, 코드의 가독성을 높일 수 있다.
from collections import namedtuple
# namedtuple 정의 - 'Person'은 타입 이름, 리스트는 필드 이름
Person = namedtuple('Person', ['name', 'age', 'city'])
# 인스턴스 생성
alice = Person('Alice', 30, 'New York')
bob = Person(name='Bob', age=25, city='Boston') # 키워드 인자로도 생성 가능
# 두 가지 방법으로 접근 가능
print(alice.name) # Alice - 필드 이름으로 접근 (가독성 좋음)
print(alice[0]) # Alice - 인덱스로 접근 (기존 튜플처럼)
# 불변 객체이므로 수정 불가
# alice.age = 31 # AttributeError 발생
# 일부 필드 수정한 새 객체 생성
carol = alice._replace(age=31, city='Chicago')
print(carol) # Person(name='Alice', age=31, city='Chicago')
# 필드 이름 목록과 값 목록 얻기
print(alice._fields) # ('name', 'age', 'city')
print(tuple(alice)) # ('Alice', 30, 'New York')
# 딕셔너리로 변환
person_dict = alice._asdict()
print(person_dict) # {'name': 'Alice', 'age': 30, 'city': 'New York'}
Enum 활용
enum 모듈은 열거형(enumeration) 타입을 제공하며, 고정된 상수들의 집합을 정의할 때 사용된다. 열거형을 사용하면 가독성을 높이고, 잘못된 값이 사용되는 것을 방지할 수 있다.
enum.Enum - 열거형 타입
이름이 있는 상수 값의 집합을 정의할 수 있는 클래스이다. 의미없는 숫자 대신 의미 있는 이름으로 상수를 관리할 수 있어 코드 가독성과 유지보수성이 향상된다.
from enum import Enum
# 기본 열거형 정의
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# 열거형 멤버 사용
print(Color.RED) # Color.RED (열거형 멤버)
print(Color.RED.name) # RED (이름)
print(Color.RED.value) # 1 (값)
# 값으로 멤버 찾기
print(Color(1)) # Color.RED
print(Color['RED']) # Color.RED
# 열거형 순회
for color in Color:
print(f"{color.name}: {color.value}")
# RED: 1
# GREEN: 2
# BLUE: 3
# 비교 연산
print(Color.RED == Color.RED) # True
print(Color.RED == Color(1)) # True
print(Color.RED == 1) # False (값과 직접 비교 불가)
IntEnum - 정수와 비교 가능한 열거형
IntEnum은 모든 값이 정수이며, 정수와 직접 비교할 수 있는 열거형이다. 열거형의 장점을 유지하면서도 정수 기반 API와 호환성을 유지할 수 있다.
from enum import IntEnum
class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3
# 정수와 직접 비교 가능
print(Priority.LOW < Priority.HIGH) # True
print(Priority.MEDIUM == 2) # True (일반 Enum과 달리 가능)
print(Priority.HIGH > 2) # True
# 정수 연산 가능
print(Priority.LOW + 10) # 11 (정수로 변환됨)
# 정수처럼 활용 가능
priorities = [Priority.MEDIUM, Priority.LOW, Priority.HIGH]
print(sorted(priorities)) # [<Priority.LOW: 1>, <Priority.MEDIUM: 2>, <Priority.HIGH: 3>]
Flag - 비트 플래그로 사용 가능한 열거형
Flag는 비트 연산을 사용하여 여러 옵션을 조합할 수 있는 열거형이다. 권한 관리, 상태 플래그, 옵션 설정 등에서 여러 값을 동시에 표현하는 사용할 수 있다.
from enum import Flag, auto
class Permission(Flag):
NONE = 0
READ = auto() # 1 (2^0) 0001
WRITE = auto() # 2 (2^1) 0010
EXECUTE = auto() # 4 (2^2) 0100
# 복합 권한 (비트 OR 연산으로 정의)
READ_WRITE = READ | WRITE # 3 0011
ALL = READ | WRITE | EXECUTE # 7 0111
# 플래그 조합
user_permission = Permission.READ | Permission.WRITE
print(user_permission) # Permission.READ|WRITE
# 멤버십 테스트
print(Permission.READ in user_permission) # True
print(Permission.EXECUTE in user_permission) # False
# 복합 플래그 테스트
print(user_permission == Permission.READ_WRITE) # True
Enum을 사용하는 이유
코드 가독성 향상
# 열거형 없이:
if status == 200: # 의미가 불명확
# ...
# 열거형 사용:
if status == HttpStatus.OK: # 의미가 명확함
# ...
동일한 값이라도 서로 다른 Enum은 비교 시 다름
class Status(Enum):
PENDING = 1
ACTIVE = 2
class Priority(Enum):
LOW = 1
HIGH = 2
print(Status.PENDING == Priority.LOW) # False (둘 다 값은 1이지만 enum이 다름)
타입 안정성을 보장
class HttpStatus(Enum):
OK = 200
NOT_FOUND = 404
class DbStatus(Enum):
OK = 200
ERROR = 500
def check_http_status(status: HttpStatus): # 함수가 HttpStatus만 받는다는 것이 명확함
if status == HttpStatus.OK:
print("HTTP 요청 성공")
def check_db_status(status: DbStatus): # 함수가 DbStatus 받는다는 것이 명확함
if status == DbStatus.OK:
print("DB 작업 성공")
check_http_status(HttpStatus.OK) # HTTP 요청 성공
check_http_status(DbStatus.OK) # 값은 200으로 같지만 다른 Enum이라 실행되지 않음
'python' 카테고리의 다른 글
파이썬 기초 - 멀티 프로세싱 (0) | 2025.03.25 |
---|---|
파이썬 기초 - 멀티 스레드 (0) | 2025.03.25 |
파이썬 기초 - 메타 클래스와 추상 클래스 (0) | 2025.03.23 |
파이썬 기초 - 메서드 유형과 매직 메서드 (0) | 2025.03.22 |
파이썬 기초 - 클래스 속성 관리와 접근 제어 (0) | 2025.03.20 |
댓글