[2026] Python 자료형 | 리스트, 딕셔너리, 튜플, 세트 완벽 가이드

[2026] Python 자료형 | 리스트, 딕셔너리, 튜플, 세트 완벽 가이드

이 글의 핵심

Python 자료형: 리스트, 딕셔너리, 튜플, 세트 리스트 (List)·딕셔너리 (Dictionary).

들어가며

Python의 내장 자료형(언어에 기본으로 들어 있는 데이터 종류)은 강력하고 사용하기 쉽습니다. 이 글에서는 리스트, 딕셔너리, 튜플, 세트를 완벽하게 마스터합니다. 자료구조 관점(시간 복잡도·알고리즘 문제 풀이)은 배열과 리스트, 스택과 큐, 해시 테이블 글과 함께 보면 이해가 깊어집니다.

실무 활용 사례: 데이터 분석, 웹 개발, 자동화 프로젝트에서 실제로 사용한 패턴과 코드를 바탕으로 정리했습니다. 초보자가 흔히 겪는 오류와 해결법을 포함합니다.

실무에서 느낀 Python의 매력

처음 Python을 배울 때는 “이게 정말 프로그래밍 언어인가?” 싶을 정도로 간결했습니다. C++에서 10줄로 작성하던 코드가 Python에서는 2~3줄로 끝나는 경우가 많았죠. 특히 데이터 분석 프로젝트를 진행하면서 Pandas와 NumPy의 강력함을 체감했습니다. 엑셀로 몇 시간 걸리던 작업이 Python 스크립트로는 몇 초 만에 끝나는 걸 보고 동료들이 놀라워했던 기억이 납니다. 하지만 처음부터 순탄하지만은 않았습니다. 들여쓰기 하나 잘못해서 몇 시간을 헤맨 적도 있고, 가상환경 설정이 꼬여서 프로젝트 전체를 다시 시작한 적도 있습니다. 이런 시행착오를 겪으며 깨달은 건, 환경 설정을 처음부터 제대로 하는 것이 얼마나 중요한지였습니다. 이 글에서는 제가 겪은 실수들을 바탕으로, 여러분이 같은 시행착오를 겪지 않도록 실전 팁을 담았습니다.

1. 리스트 (List)

리스트란?

리스트(List)순서가 있고 수정 가능한(mutable) 자료형입니다. 여러 타입의 요소를 담을 수 있습니다. 쇼핑할 때 장바구니에 물건을 순서대로 넣었다가 뺄 수 있는 것과 비슷하게, 끝에 추가(append)하거나 중간을 바꾸는 일이 자유롭습니다. 특징:

  • ✅ 순서 유지 (인덱스로 접근)
  • ✅ 중복 허용
  • ✅ 수정 가능 (추가, 삭제, 변경)
  • ✅ 다양한 타입 혼합 가능

리스트 생성과 접근

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 리스트 생성
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True, [1, 2]]  # 중첩 리스트 가능
# 빈 리스트
empty1 = []
empty2 = list()
# range로 리스트 생성
nums = list(range(10))
print(nums)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 인덱싱 (0부터 시작)
print(fruits[0])   # apple (첫 번째)
print(fruits[1])   # banana (두 번째)
print(fruits[-1])  # cherry (뒤에서 첫 번째)
print(fruits[-2])  # banana (뒤에서 두 번째)
# 인덱스 범위 체크
# print(fruits[10])  # IndexError: list index out of range
# 슬라이싱 [시작:끝:간격]
print(numbers[1:4])    # [2, 3, 4] (인덱스 1~3)
print(numbers[:3])     # [1, 2, 3] (처음부터 인덱스 2까지)
print(numbers[2:])     # [3, 4, 5] (인덱스 2부터 끝까지)
print(numbers[::2])    # [1, 3, 5] (간격 2)
print(numbers[::-1])   # [5, 4, 3, 2, 1] (역순)
# 슬라이싱은 새 리스트 반환 (원본 변경 안 됨)
sub = numbers[1:3]
sub[0] = 100
print(numbers)  # [1, 2, 3, 4, 5] (원본 그대로)
print(sub)      # [100, 3]

리스트 메서드 상세

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

fruits = ["apple", "banana"]
# 추가 메서드
fruits.append("cherry")  # 끝에 하나 추가
print(fruits)  # ['apple', 'banana', 'cherry']
fruits.insert(1, "orange")  # 인덱스 1에 삽입 (기존 요소는 뒤로)
print(fruits)  # ['apple', 'orange', 'banana', 'cherry']
fruits.extend(["grape", "kiwi"])  # 여러 개 추가 (리스트 병합)
print(fruits)  # ['apple', 'orange', 'banana', 'cherry', 'grape', 'kiwi']
# append vs extend 차이
list1 = [1, 2, 3]
list1.append([4, 5])  # 리스트 자체를 요소로 추가
print(list1)  # [1, 2, 3, [4, 5]]
list2 = [1, 2, 3]
list2.extend([4, 5])  # 요소들을 개별적으로 추가
print(list2)  # [1, 2, 3, 4, 5]
# 삭제 메서드
fruits = ["apple", "banana", "cherry", "banana"]
fruits.remove("banana")  # 첫 번째 "banana" 삭제
print(fruits)  # ['apple', 'cherry', 'banana']
del fruits[0]  # 인덱스로 삭제
print(fruits)  # ['cherry', 'banana']
last = fruits.pop()  # 마지막 요소 제거 및 반환
print(last)    # banana
print(fruits)  # ['cherry']
second = fruits.pop(0)  # 특정 인덱스 제거 및 반환
print(second)  # cherry
fruits.clear()  # 전체 삭제
print(fruits)  # []
# 검색 메서드
fruits = ["apple", "banana", "cherry", "banana"]
index = fruits.index("banana")  # 첫 번째 위치
print(index)  # 1
# index("banana", 2)  # 인덱스 2부터 검색
# fruits.index("grape")  # ValueError: 'grape' is not in list
count = fruits.count("banana")  # 개수 세기
print(count)  # 2
# in 연산자
print("apple" in fruits)  # True
print("grape" in fruits)  # False
# 정렬 메서드
numbers = [3, 1, 4, 1, 5, 9, 2]
# sort(): 원본 변경
numbers.sort()
print(numbers)  # [1, 1, 2, 3, 4, 5, 9]
numbers.sort(reverse=True)  # 내림차순
print(numbers)  # [9, 5, 4, 3, 2, 1, 1]
# sorted(): 새 리스트 반환 (원본 유지)
numbers = [3, 1, 4, 1, 5]
sorted_nums = sorted(numbers)
print(numbers)      # [3, 1, 4, 1, 5] (원본 그대로)
print(sorted_nums)  # [1, 1, 3, 4, 5]
# key 함수로 정렬
words = ["banana", "pie", "Washington", "book"]
words.sort(key=len)  # 길이 순
print(words)  # ['pie', 'book', 'banana', 'Washington']
words.sort(key=str.lower)  # 대소문자 무시
print(words)  # ['banana', 'book', 'pie', 'Washington']
# 뒤집기
numbers = [1, 2, 3, 4, 5]
numbers.reverse()  # 원본 변경
print(numbers)  # [5, 4, 3, 2, 1]
# 또는 슬라이싱
reversed_nums = numbers[::-1]  # 새 리스트

리스트 연산

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 연결 (+)
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2
print(combined)  # [1, 2, 3, 4, 5, 6]
# 반복 (*)
repeated = [1, 2] * 3
print(repeated)  # [1, 2, 1, 2, 1, 2]
# 길이
print(len(fruits))  # 요소 개수
# 최대/최소/합계
numbers = [3, 1, 4, 1, 5]
print(max(numbers))  # 5
print(min(numbers))  # 1
print(sum(numbers))  # 14

리스트 컴프리헨션 (상세)

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 기본: [표현식 for 변수 in 반복가능객체]
squares = [x**2 for x in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 조건 포함: [표현식 for 변수 in 반복가능객체 if 조건]
evens = [x for x in range(10) if x % 2 == 0]
print(evens)  # [0, 2, 4, 6, 8]
# if-else: [표현식1 if 조건 else 표현식2 for 변수 in 반복가능객체]
labels = ['짝수' if x % 2 == 0 else '홀수' for x in range(5)]
print(labels)  # ['짝수', '홀수', '짝수', '홀수', '짝수']
# 중첩: 2차원 리스트 생성
matrix = [[i*j for j in range(3)] for i in range(3)]
print(matrix)
# [[0, 0, 0],
#  [0, 1, 2],
#  [0, 2, 4]]
# 평탄화
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

리스트 복사 주의사항

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 얕은 복사 (shallow copy)
list1 = [1, 2, 3]
list2 = list1  # 참조 복사 (같은 객체)
list2[0] = 100
print(list1)  # [100, 2, 3] (list1도 변경됨!)
# 깊은 복사 방법
list1 = [1, 2, 3]
list2 = list1.copy()  # 방법 1
list3 = list1[:]      # 방법 2
list4 = list(list1)   # 방법 3
list2[0] = 100
print(list1)  # [1, 2, 3] (원본 유지)
print(list2)  # [100, 2, 3]
# 중첩 리스트는 얕은 복사
matrix = [[1, 2], [3, 4]]
matrix_copy = matrix.copy()
matrix_copy[0][0] = 100
print(matrix)  # [[100, 2], [3, 4]] (원본도 변경!)
# 완전한 깊은 복사
import copy
matrix_deep = copy.deepcopy(matrix)
matrix_deep[0][0] = 999
print(matrix)      # [[100, 2], [3, 4]] (원본 유지)
print(matrix_deep) # [[999, 2], [3, 4]]

2. 딕셔너리 (Dictionary)

기본 사용법

딕셔너리이름표(키)로 값을 찾는 전화번호부와 비슷합니다. 리스트처럼 순번(0, 1, 2…)으로 찾기보다 의미 있는 키로 저장하므로, 설정 값·사용자 프로필처럼 “항목 이름 → 내용” 구조에 잘 맞습니다. 다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 딕셔너리 생성
person = {
    "name": "홍길동",
    "age": 25,
    "city": "서울"
}
# 접근
print(person[name])      # 홍길동
print(person.get("age"))   # 25
print(person.get("job", "없음"))  # 기본값
# 추가/수정
person[job] = "개발자"   # 추가
person[age] = 26         # 수정
# 삭제
del person[city]
job = person.pop("job")    # 제거 및 반환

딕셔너리 메서드

다음은 python를 활용한 상세한 구현 코드입니다. 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

person = {"name": "홍길동", "age": 25}
# 키/값/아이템
keys = person.keys()      # dict_keys(['name', 'age'])
values = person.values()  # dict_values(['홍길동', 25])
items = person.items()    # dict_items([('name', '홍길동'), ('age', 25)])
# 순회 방법
# 방법 1: 키만
for key in person:
    print(key, person[key])
# 방법 2: 키-값 (권장)
for key, value in person.items():
    print(f"{key}: {value}")
# name: 홍길동
# age: 25
# update(): 딕셔너리 병합
person.update({"city": "서울", "job": "개발자"})  # age는 덮어씀
print(person)  # {'name': '홍길동', 'age': 25, 'city': '서울', 'job': '개발자'}
# setdefault(): 키가 없을 때만 추가
person.setdefault("country", "한국")  # 추가
print(person[country])  # 한국
person.setdefault("name", "김철수")  # 이미 있으므로 무시
print(person[name])  # 홍길동 (변경 안 됨)
# popitem(): 마지막 키-값 쌍 제거 (Python 3.7+)
last = person.popitem()
print(last)  # ('country', '한국')

딕셔너리 컴프리헨션

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 기본: {키표현식: 값표현식 for 변수 in 반복가능객체}
squares = {x: x**2 for x in range(5)}
print(squares)  # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 조건 포함
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
print(even_squares)  # {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# 키-값 교환
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(swapped)  # {1: 'a', 2: 'b', 3: 'c'}
# 리스트를 딕셔너리로
names = ["Alice", "Bob", "Charlie"]
name_dict = {i: name for i, name in enumerate(names)}
print(name_dict)  # {0: 'Alice', 1: 'Bob', 2: 'Charlie'}

중첩 딕셔너리

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 중첩 딕셔너리
users = {
    "user1": {"name": "홍길동", "age": 25},
    "user2": {"name": "김철수", "age": 30}
}
# 접근
print(users[user1][name])  # 홍길동
# 안전한 접근
name = users.get("user1", {}).get("name", "없음")
print(name)  # 홍길동
# 존재하지 않는 키
name = users.get("user3", {}).get("name", "없음")
print(name)  # 없음 (에러 없음)

defaultdict 활용

다음은 python를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

from collections import defaultdict
# 기본 딕셔너리 문제
word_count = {}
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
for word in words:
    if word not in word_count:
        word_count[word] = 0
    word_count[word] += 1
print(word_count)  # {'apple': 3, 'banana': 2, 'cherry': 1}
# defaultdict 사용
word_count = defaultdict(int)  # 기본값 0
for word in words:
    word_count[word] += 1  # 키가 없어도 자동으로 0으로 초기화
print(dict(word_count))  # {'apple': 3, 'banana': 2, 'cherry': 1}
# 리스트를 기본값으로
groups = defaultdict(list)
students = [("홍길동", "A"), ("김철수", "B"), ("이영희", "A")]
for name, grade in students:
    groups[grade].append(name)
print(dict(groups))  # {'A': ['홍길동', '이영희'], 'B': ['김철수']}

3. 튜플 (Tuple)

튜플이란?

튜플(Tuple)순서가 있고 수정 불가능한(immutable) 자료형입니다. 리스트와 비슷하지만 한 번 생성하면 변경할 수 없습니다. 특징:

  • ✅ 순서 유지
  • ✅ 중복 허용
  • ❌ 수정 불가 (추가, 삭제, 변경 불가)
  • ✅ 리스트보다 메모리 효율적
  • ✅ 딕셔너리 키로 사용 가능 언제 사용하나?
  • 변경되면 안 되는 데이터 (좌표, 설정값)
  • 함수에서 여러 값 반환
  • 딕셔너리 키로 사용

튜플 생성과 접근

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 튜플 생성
point = (10, 20)
person = ("홍길동", 25, "서울")
single = (42,)  # 요소 1개일 때 쉼표 필수!
# 괄호 없이도 가능
coords = 10, 20, 30
print(type(coords))  # <class 'tuple'>
# 빈 튜플
empty1 = ()
empty2 = tuple()
# 리스트를 튜플로
numbers = tuple([1, 2, 3, 4, 5])
print(numbers)  # (1, 2, 3, 4, 5)
# 인덱싱/슬라이싱 (리스트와 동일)
print(person[0])    # 홍길동
print(person[-1])   # 서울
print(person[1:])   # (25, '서울')
# ❌ 수정 불가
# person[1] = 26  # TypeError: 'tuple' object does not support item assignment
# person.append(100)  # AttributeError: 'tuple' object has no attribute 'append'
# 튜플 메서드 (2개만 존재)
numbers = (1, 2, 3, 2, 4, 2)
print(numbers.count(2))  # 3 (2의 개수)
print(numbers.index(3))  # 2 (3의 인덱스)

튜플 언패킹 (Unpacking)

다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 기본 언패킹
name, age, city = ("홍길동", 25, "서울")
print(name, age, city)  # 홍길동 25 서울
# 함수 반환값
def get_user():
    return "홍길동", 25, "서울"  # 튜플 반환
name, age, city = get_user()
print(name)  # 홍길동
# 값 교환 (Python의 강력한 기능)
a, b = 1, 2
a, b = b, a  # 교환
print(a, b)  # 2 1
# * 연산자로 나머지 받기
numbers = (1, 2, 3, 4, 5)
first, *rest, last = numbers
print(first)  # 1
print(rest)   # [2, 3, 4] (리스트!)
print(last)   # 5
# 여러 변수에 동시 할당
x, y, z = 10, 20, 30
print(x, y, z)  # 10 20 30

튜플 vs 리스트 비교

특징튜플리스트
수정 가능
속도빠름느림
메모리적음많음
메서드2개11개
딕셔너리 키
사용 시점불변 데이터가변 데이터
아래 코드는 python를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
import sys
# 메모리 비교
list_data = [1, 2, 3, 4, 5]
tuple_data = (1, 2, 3, 4, 5)
print(sys.getsizeof(list_data))   # 104 bytes
print(sys.getsizeof(tuple_data))  # 80 bytes
# 딕셔너리 키로 사용
# locations = {[10, 20]: "A"}  # TypeError: unhashable type: 'list'
locations = {(10, 20): "A", (30, 40): "B"}  # 튜플은 가능
print(locations[(10, 20)])  # A

튜플의 불변성 주의사항

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 튜플 자체는 불변이지만, 내부 가변 객체는 변경 가능
tuple_with_list = (1, 2, [3, 4])
# tuple_with_list[0] = 100  # TypeError (튜플 요소 변경 불가)
tuple_with_list[2].append(5)  # 내부 리스트는 변경 가능
print(tuple_with_list)  # (1, 2, [3, 4, 5])
# 튜플 "수정" (실제로는 새 튜플 생성)
original = (1, 2, 3)
modified = original + (4, 5)  # 새 튜플
print(original)  # (1, 2, 3)
print(modified)  # (1, 2, 3, 4, 5)

4. 세트 (Set)

세트란?

세트(Set)순서가 없고 중복을 허용하지 않는 자료형입니다. 수학의 집합과 동일합니다. 특징:

  • ❌ 순서 없음 (인덱스 접근 불가)
  • ❌ 중복 불가 (자동 제거)
  • ✅ 수정 가능 (추가, 삭제)
  • ✅ 멤버십 테스트 빠름 (O(1))
  • ✅ 집합 연산 지원 언제 사용하나?
  • 중복 제거
  • 멤버십 테스트 (in 연산)
  • 집합 연산 (합집합, 교집합, 차집합)

세트 생성과 연산

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 세트 생성
fruits = {"apple", "banana", "cherry"}
numbers = {1, 2, 3, 4, 5}
# 빈 세트 (주의: {}는 딕셔너리!)
empty = set()  # 올바른 방법
# empty = {}  # 이건 딕셔너리!
# 리스트를 세트로 (중복 제거)
numbers = [1, 2, 2, 3, 3, 3, 4]
unique = set(numbers)
print(unique)  # {1, 2, 3, 4}
# 문자열을 세트로
chars = set("hello")
print(chars)  # {'h', 'e', 'l', 'o'} (중복 'l' 제거)
# 추가
fruits = {"apple", "banana"}
fruits.add("cherry")
print(fruits)  # {'apple', 'banana', 'cherry'}
fruits.add("apple")  # 중복은 무시됨
print(fruits)  # {'apple', 'banana', 'cherry'}
# 여러 개 추가
fruits.update(["orange", "grape"])
print(fruits)  # {'apple', 'banana', 'cherry', 'orange', 'grape'}
# 삭제
fruits.remove("banana")  # 없으면 KeyError
print(fruits)  # {'apple', 'cherry', 'orange', 'grape'}
fruits.discard("grape")  # 없어도 에러 안 남
fruits.discard("kiwi")   # 에러 없음
# pop(): 임의의 요소 제거 (순서 없으므로 어떤 요소인지 모름)
item = fruits.pop()
print(item)  # 임의의 과일
fruits.clear()  # 전체 삭제

집합 연산 상세

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# 합집합 (Union): 두 집합의 모든 요소
print(a | b)           # {1, 2, 3, 4, 5, 6}
print(a.union(b))      # {1, 2, 3, 4, 5, 6}
# 교집합 (Intersection): 공통 요소
print(a & b)              # {3, 4}
print(a.intersection(b))  # {3, 4}
# 차집합 (Difference): a에만 있는 요소
print(a - b)            # {1, 2}
print(a.difference(b))  # {1, 2}
# 대칭 차집합 (Symmetric Difference): 한쪽에만 있는 요소
print(a ^ b)                      # {1, 2, 5, 6}
print(a.symmetric_difference(b))  # {1, 2, 5, 6}
# 부분집합/상위집합 확인
c = {1, 2}
print(c.issubset(a))    # True (c는 a의 부분집합)
print(a.issuperset(c))  # True (a는 c의 상위집합)
# 서로소 집합 확인
d = {7, 8, 9}
print(a.isdisjoint(d))  # True (공통 요소 없음)
print(a.isdisjoint(b))  # False (3, 4가 공통)

세트 실전 활용

다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 1. 중복 제거 (순서 유지 필요 없을 때)
emails = ["a@test.com", "b@test.com", "a@test.com", "c@test.com"]
unique_emails = list(set(emails))
print(unique_emails)  # ['a@test.com', 'b@test.com', 'c@test.com']
# 2. 중복 제거 (순서 유지 필요할 때)
def remove_duplicates(items):
    seen = set()
    result = []
    for item in items:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result
emails = ["a@test.com", "b@test.com", "a@test.com", "c@test.com"]
unique = remove_duplicates(emails)
print(unique)  # ['a@test.com', 'b@test.com', 'c@test.com']
# 3. 빠른 멤버십 테스트
# 리스트: O(n)
large_list = list(range(100000))
# 10000 in large_list  # 느림
# 세트: O(1)
large_set = set(range(100000))
# 10000 in large_set  # 빠름
# 4. 두 리스트의 공통 요소
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = list(set(list1) & set(list2))
print(common)  # [4, 5]

실전 예제

예제 1: 학생 성적 관리 시스템

# 학생 데이터 (리스트 + 딕셔너리)
students = [
    {"name": "홍길동", "scores": [85, 90, 78]},
    {"name": "김철수", "scores": [92, 88, 95]},
    {"name": "이영희", "scores": [78, 82, 80]}
]
# 평균 계산 및 등급 부여
for student in students:
    avg = sum(student[scores]) / len(student[scores])
    
    if avg >= 90:
        grade = "A"
    elif avg >= 80:
        grade = "B"
    else:
        grade = "C"
    
    print(f"{student['name']}: 평균 {avg:.1f}, 등급 {grade}")
# 출력:
# 홍길동: 평균 84.3, 등급 B
# 김철수: 평균 91.7, 등급 A
# 이영희: 평균 80.0, 등급 B

예제 2: 텍스트 분석 (딕셔너리 + 세트)

text = """
Python is powerful. Python is easy.
Python is popular. Python is versatile.
"""
# 단어 추출 (소문자 변환, 구두점 제거)
words = text.lower().replace(".", "").split()
# 단어 빈도 (딕셔너리)
word_count = {}
for word in words:
    word_count[word] = word_count.get(word, 0) + 1
# 빈도순 정렬
sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
print("단어 빈도:")
for word, count in sorted_words[:5]:  # 상위 5개
    print(f"  {word}: {count}")
# 고유 단어 개수 (세트)
unique_words = set(words)
print(f"\n고유 단어 수: {len(unique_words)}")
# 출력:
# 단어 빈도:
#   python: 4
#   is: 4
#   powerful: 1
#   easy: 1
#   popular: 1
# 
# 고유 단어 수: 6

예제 3: 장바구니 시스템 (딕셔너리 + 리스트)

다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 상품 정보
products = {
    "P001": {"name": "노트북", "price": 1200000},
    "P002": {"name": "마우스", "price": 30000},
    "P003": {"name": "키보드", "price": 80000}
}
# 장바구니 (상품ID: 수량)
cart = {}
# 상품 추가
def add_to_cart(product_id, quantity=1):
    if product_id in products:
        cart[product_id] = cart.get(product_id, 0) + quantity
        print(f"{products[product_id]['name']} {quantity}개 추가")
    else:
        print("존재하지 않는 상품입니다.")
# 총액 계산
def calculate_total():
    total = 0
    for product_id, quantity in cart.items():
        price = products[product_id][price]
        total += price * quantity
    return total
# 실행
add_to_cart("P001", 1)  # 노트북 1개 추가
add_to_cart("P002", 2)  # 마우스 2개 추가
add_to_cart("P003", 1)  # 키보드 1개 추가
print(f"\n총액: {calculate_total():,}원")  # 총액: 1,340,000원

예제 4: 친구 추천 시스템 (세트)

다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 사용자별 친구 목록
friends = {
    "홍길동": {"김철수", "이영희", "박민수"},
    "김철수": {"홍길동", "박민수", "최지훈"},
    "이영희": {"홍길동", "최지훈", "정수진"}
}
# 공통 친구 찾기
def find_common_friends(user1, user2):
    return friends[user1] & friends[user2]
# 친구 추천 (친구의 친구 - 나와 내 친구 제외)
def recommend_friends(user):
    my_friends = friends[user]
    candidates = set()
    
    for friend in my_friends:
        candidates.update(friends[friend])
    
    # 나 자신과 이미 친구인 사람 제외
    recommendations = candidates - my_friends - {user}
    return recommendations
print("홍길동과 김철수의 공통 친구:", find_common_friends("홍길동", "김철수"))
# 홍길동과 김철수의 공통 친구: {'박민수'}
print("홍길동에게 추천할 친구:", recommend_friends("홍길동"))
# 홍길동에게 추천할 친구: {'최지훈', '정수진'}

예제 5: 데이터 변환 파이프라인

# CSV 데이터 (문자열)
csv_data = """name,age,city
홍길동,25,서울
김철수,30,부산
이영희,28,서울
박민수,35,대구"""
# 1단계: 문자열 → 리스트
lines = csv_data.strip().split("\n")
header = lines[0].split(",")
rows = [line.split(",") for line in lines[1:]]
# 2단계: 리스트 → 딕셔너리 리스트
users = []
for row in rows:
    user = {}
    for i, key in enumerate(header):
        user[key] = row[i]
    users.append(user)
print("딕셔너리 리스트:")
for user in users:
    print(user)
# 3단계: 도시별 그룹핑 (딕셔너리 + 리스트)
city_groups = {}
for user in users:
    city = user[city]
    if city not in city_groups:
        city_groups[city] = []
    city_groups[city].append(user[name])
print("\n도시별 사용자:")
for city, names in city_groups.items():
    print(f"{city}: {', '.join(names)}")
# 4단계: 고유 도시 (세트)
cities = {user[city] for user in users}
print(f"\n고유 도시: {cities}")
# 출력:
# 딕셔너리 리스트:
# {'name': '홍길동', 'age': '25', 'city': '서울'}
# {'name': '김철수', 'age': '30', 'city': '부산'}
# {'name': '이영희', 'age': '28', 'city': '서울'}
# {'name': '박민수', 'age': '35', 'city': '대구'}
# 
# 도시별 사용자:
# 서울: 홍길동, 이영희
# 부산: 김철수
# 대구: 박민수
# 
# 고유 도시: {'서울', '부산', '대구'}

성능 비교와 선택 가이드

시간 복잡도 비교

연산리스트튜플딕셔너리세트
인덱스 접근O(1)O(1)--
키/값 접근--O(1)-
검색 (in)O(n)O(n)O(1)O(1)
추가 (끝)O(1)-O(1)O(1)
삽입 (중간)O(n)---
삭제O(n)-O(1)O(1)
정렬O(n log n)---

자료형 선택 가이드

다음은 python를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 1. 순서가 중요하고 수정이 필요한 경우 → 리스트
todo_list = ["코딩", "운동", "독서"]
todo_list.append("명상")
# 2. 순서가 중요하지만 수정이 불필요한 경우 → 튜플
coordinates = (37.5665, 126.9780)  # 서울 좌표 (변경 불가)
# 3. 키로 빠르게 접근해야 하는 경우 → 딕셔너리
user_db = {"user123": {"name": "홍길동", "email": "hong@test.com"}}
user = user_db[user123]  # O(1) 접근
# 4. 중복 제거나 집합 연산이 필요한 경우 → 세트
tags1 = {"python", "coding", "tutorial"}
tags2 = {"python", "web", "tutorial"}
common_tags = tags1 & tags2  # {'python', 'tutorial'}
# 5. 빠른 멤버십 테스트가 필요한 경우 → 세트
allowed_users = {"admin", "user1", "user2"}  # 세트 (빠름)
if username in allowed_users:  # O(1)
    grant_access()

자주 하는 실수와 해결법

실수 1: 빈 세트를 {}로 생성

아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# ❌ 잘못된 방법
empty = {}
print(type(empty))  # <class 'dict'> (딕셔너리!)
# ✅ 올바른 방법
empty = set()
print(type(empty))  # <class 'set'>

실수 2: 리스트 복사 시 참조 문제

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ❌ 잘못된 방법
list1 = [1, 2, 3]
list2 = list1  # 참조만 복사
list2[0] = 100
print(list1)  # [100, 2, 3] (원본도 변경!)
# ✅ 올바른 방법
list1 = [1, 2, 3]
list2 = list1.copy()  # 또는 list1[:] 또는 list(list1)
list2[0] = 100
print(list1)  # [1, 2, 3] (원본 유지)

실수 3: 딕셔너리 키 에러

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ❌ 잘못된 방법
person = {"name": "홍길동"}
# print(person[age])  # KeyError: 'age'
# ✅ 올바른 방법 1: get() 사용
age = person.get("age", 0)  # 기본값 0
print(age)  # 0
# ✅ 올바른 방법 2: in 체크
if "age" in person:
    print(person[age])
else:
    print("나이 정보 없음")

실수 4: 튜플 요소 1개 생성

아래 코드는 python를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# ❌ 잘못된 방법
single = (42)
print(type(single))  # <class 'int'> (정수!)
# ✅ 올바른 방법
single = (42,)  # 쉼표 필수
print(type(single))  # <class 'tuple'>

실수 5: 세트는 순서가 없음

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# ❌ 잘못된 방법
numbers = {3, 1, 4, 1, 5}
# print(numbers[0])  # TypeError: 'set' object is not subscriptable
# ✅ 올바른 방법: 리스트로 변환 후 접근
numbers_list = list(numbers)
print(numbers_list[0])  # 1 (정렬되지 않은 순서)
# 정렬이 필요하면
sorted_numbers = sorted(numbers)
print(sorted_numbers)  # [1, 3, 4, 5]

고급 활용 패턴

패턴 1: 리스트 필터링과 변환

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 데이터
users = [
    {"name": "홍길동", "age": 25, "active": True},
    {"name": "김철수", "age": 17, "active": False},
    {"name": "이영희", "age": 30, "active": True}
]
# 활성 성인 사용자만 추출
active_adults = [
    user[name] 
    for user in users 
    if user[age] >= 18 and user[active]
]
print(active_adults)  # ['홍길동', '이영희']

패턴 2: 딕셔너리 병합 (Python 3.9+)

아래 코드는 python를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 방법 1: | 연산자 (Python 3.9+)
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 3, "c": 4}
merged = dict1 | dict2  # dict2가 우선
print(merged)  # {'a': 1, 'b': 3, 'c': 4}
# 방법 2: update()
dict1 = {"a": 1, "b": 2}
dict1.update(dict2)
print(dict1)  # {'a': 1, 'b': 3, 'c': 4}
# 방법 3: ** 언패킹
merged = {**dict1, **dict2}
print(merged)  # {'a': 1, 'b': 3, 'c': 4}

패턴 3: 리스트를 딕셔너리로 그룹핑

from collections import defaultdict
# 데이터
transactions = [
    ("2026-03-01", "식비", 15000),
    ("2026-03-01", "교통비", 5000),
    ("2026-03-02", "식비", 20000),
    ("2026-03-02", "쇼핑", 50000),
    ("2026-03-03", "식비", 12000)
]
# 날짜별 그룹핑
by_date = defaultdict(list)
for date, category, amount in transactions:
    by_date[date].append((category, amount))
print("날짜별 지출:")
for date, items in by_date.items():
    total = sum(amount for _, amount in items)
    print(f"{date}: {total:,}원")
# 카테고리별 합계
by_category = defaultdict(int)
for _, category, amount in transactions:
    by_category[category] += amount
print("\n카테고리별 지출:")
for category, total in by_category.items():
    print(f"{category}: {total:,}원")
# 출력:
# 날짜별 지출:
# 2026-03-01: 20,000원
# 2026-03-02: 70,000원
# 2026-03-03: 12,000원
# 
# 카테고리별 지출:
# 식비: 47,000원
# 교통비: 5,000원
# 쇼핑: 50,000원

패턴 4: 세트로 권한 관리

다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

# 역할별 권한
permissions = {
    "admin": {"read", "write", "delete", "manage_users"},
    "editor": {"read", "write"},
    "viewer": {"read"}
}
# 사용자 역할
user_roles = {
    "홍길동": [admin],
    "김철수": ["editor", "viewer"],
    "이영희": [viewer]
}
# 사용자의 모든 권한 계산
def get_user_permissions(username):
    user_perms = set()
    for role in user_roles.get(username, []):
        user_perms.update(permissions.get(role, set()))
    return user_perms
# 권한 확인
def has_permission(username, permission):
    return permission in get_user_permissions(username)
# 테스트
print("홍길동 권한:", get_user_permissions("홍길동"))
# {'read', 'write', 'delete', 'manage_users'}
print("김철수 권한:", get_user_permissions("김철수"))
# {'read', 'write'}
print("이영희가 write 가능?", has_permission("이영희", "write"))
# False

연습 문제

문제 1: 리스트 회전

리스트를 오른쪽으로 k번 회전하세요. 아래 코드는 python를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

def rotate_list(nums, k):
    if not nums or k == 0:
        return nums
    k = k % len(nums)  # k가 리스트 길이보다 클 경우
    return nums[-k:] + nums[:-k]
# 테스트
print(rotate_list([1, 2, 3, 4, 5], 2))  # [4, 5, 1, 2, 3]
print(rotate_list([1, 2, 3, 4, 5], 7))  # [4, 5, 1, 2, 3] (7 % 5 = 2)

문제 2: 두 딕셔너리의 차이 찾기

두 딕셔너리를 비교하여 다른 키-값 쌍을 찾으세요. 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

def dict_diff(dict1, dict2):
    all_keys = set(dict1.keys()) | set(dict2.keys())
    diff = {}
    
    for key in all_keys:
        val1 = dict1.get(key)
        val2 = dict2.get(key)
        if val1 != val2:
            diff[key] = {"old": val1, "new": val2}
    
    return diff
# 테스트
old = {"name": "홍길동", "age": 25, "city": "서울"}
new = {"name": "홍길동", "age": 26, "city": "부산", "job": "개발자"}
print(dict_diff(old, new))
# {'age': {'old': 25, 'new': 26}, 
#  'city': {'old': '서울', 'new': '부산'}, 
#  'job': {'old': None, 'new': '개발자'}}

문제 3: 중첩 리스트 평탄화

중첩된 리스트를 1차원 리스트로 변환하세요. 다음은 python를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

def flatten(nested_list):
    result = []
    for item in nested_list:
        if isinstance(item, list):
            result.extend(flatten(item))  # 재귀
        else:
            result.append(item)
    return result
# 테스트
nested = [1, [2, 3], [4, [5, 6]], 7]
print(flatten(nested))  # [1, 2, 3, 4, 5, 6, 7]
# 컴프리헨션 버전 (1단계만)
nested = [[1, 2], [3, 4], [5, 6]]
flat = [num for sublist in nested for num in sublist]
print(flat)  # [1, 2, 3, 4, 5, 6]

정리

자료형 선택 가이드

자료형순서중복수정용도
리스트순서 있는 데이터, 수정 필요
튜플불변 데이터, 함수 반환값
딕셔너리✅ (3.7+)❌ (키)키-값 쌍, 빠른 조회
세트중복 제거, 집합 연산, 빠른 멤버십

핵심 요약

  1. 리스트: 가장 범용적, append(), extend(), sort() 활용
  2. 딕셔너리: 키로 빠른 접근, get(), items(), defaultdict 활용
  3. 튜플: 불변 데이터, 언패킹, 딕셔너리 키로 사용
  4. 세트: 중복 제거, in 연산 빠름, 집합 연산 지원

다음 단계


관련 글

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3