← SEARCHABLE ARCHIVE
Python · 2026-07-21

Python 기초부터 마스터까지 — 3화

리스트, 튜플, 집합, 딕셔너리와 변경 가능성 이해하기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

Python에는 여러 값을 다루는 기본 컬렉션이 있다. 비슷해 보여도 순서, 중복, 검색 방식, 변경 가능성에 따라 쓰임이 다르다.

네 가지 기본 컬렉션

party = ["Knight", "Mage", "Knight"]       # list
position = (10, 20)                          # tuple
unlocked = {101, 205, 310}                   # set
inventory = {"potion": 3, "key": 1}       # dict
  • list는 순서와 중복을 유지하며 원소를 추가하거나 삭제할 수 있다.
  • tuple은 한 번 만든 뒤 원소를 바꿀 수 없어 고정된 값 묶음에 잘 맞는다.
  • set은 중복을 제거하고 값의 존재 여부를 빠르게 확인할 때 유용하다.
  • dict는 키와 값을 연결해 키로 데이터를 찾는다.

컬렉션은 습관으로 고르기보다 보장해야 할 성질로 선택해야 한다. 플레이 순서가 중요하다면 집합으로 바꾸면 안 되고, 같은 아이템의 개수가 중요하다면 중복을 무작정 제거하면 안 된다.

딕셔너리로 데이터 집계하기

items = ["potion", "key", "potion", "potion", "map"]
counts: dict[str, int] = {}

for item in items:
    counts[item] = counts.get(item, 0) + 1

for name, count in sorted(counts.items()):
    print(f"{name}: {count}")

get(item, 0)은 키가 없을 때 0을 사용한다. 딕셔너리를 반복하면 기본적으로 키를 읽고, 키와 값이 모두 필요하면 items()를 사용한다.

같은 객체를 가리키는 이름

Python의 대입은 객체를 자동 복사하지 않는다.

original = ["sword"]
shared = original
shared.append("shield")

print(original)  # ['sword', 'shield']

두 이름이 같은 리스트를 가리키기 때문에 한쪽의 변경이 다른 쪽에서도 보인다. 독립된 얕은 복사가 필요하면 copy()를 사용할 수 있다.

original = {"items": ["sword"]}
copied = original.copy()
copied["items"].append("shield")

print(original["items"])  # ['sword', 'shield']

하지만 얕은 복사는 안쪽 리스트까지 새로 만들지 않는다. 중첩된 변경 가능 객체가 많아질수록 누가 상태를 바꾸는지 추적하기 어려워진다. 필요한 계층만 명시적으로 복사하거나 불변 객체를 사용하는 편이 좋다.

정렬과 검색

players = [
    {"name": "Rose", "score": 120},
    {"name": "Mage", "score": 180},
    {"name": "Knight", "score": 150},
]

ranking = sorted(players, key=lambda player: player["score"], reverse=True)

sorted는 새 리스트를 만들고, 리스트의 sort()는 기존 리스트를 바꾼다. 리스트에서 값의 존재를 찾는 작업은 원소 수에 따라 느려질 수 있지만 집합과 딕셔너리는 평균적으로 빠른 키 검색을 제공한다.

자료구조 선택은 성능만의 문제가 아니다. 순서, 중복, 변경 가능성, 검색 키를 먼저 정하면 코드가 데이터의 의미를 더 정확하게 표현한다.