[파이썬 100강] 06강. 리스트와 튜플 핵심 사용법

[파이썬 100강] 06강. 리스트와 튜플 핵심 사용법

리스트와 튜플은 파이썬에서 가장 자주 만나는 시퀀스 자료구조입니다. 둘 다 여러 값을 순서대로 담을 수 있지만, 변경 가능성(mutability)에서 성격이 완전히 갈립니다. 실무에서는 이 차이를 명확히 이해해야 버그를 줄이고, 함수 설계와 데이터 모델링도 안정적으로 할 수 있습니다.


핵심 개념

리스트(list)와 튜플(tuple)의 공통점은 다음과 같습니다.

  • 여러 값을 순서대로 저장한다.
  • 인덱싱, 슬라이싱이 가능하다.
  • 반복문(for)으로 쉽게 순회할 수 있다.

하지만 가장 큰 차이는 수정 가능 여부입니다.

  • 리스트: 생성 후 요소 추가/삭제/변경 가능
  • 튜플: 생성 후 요소 변경 불가(immutable)
>>> nums = [10, 20, 30]
>>> nums[1] = 99
>>> nums
[10, 99, 30]

>>> point = (3, 7)
>>> point[0] = 10
Traceback (most recent call last):
  ...
TypeError: 'tuple' object does not support item assignment

이 특성 차이 때문에, “변경될 데이터인가?”를 먼저 묻고 자료구조를 선택하는 습관이 중요합니다.


기본 사용

1) 리스트 생성/수정/확장

>>> tasks = ["백업", "로그정리", "헬스체크"]
>>> tasks.append("리포트생성")
>>> tasks
['백업', '로그정리', '헬스체크', '리포트생성']

>>> tasks.insert(1, "보안점검")
>>> tasks
['백업', '보안점검', '로그정리', '헬스체크', '리포트생성']

>>> done = tasks.pop(0)
>>> done
'백업'
>>> tasks
['보안점검', '로그정리', '헬스체크', '리포트생성']

리스트는 작업 큐, 주문 목록, 수집 데이터 버퍼처럼 “계속 변하는 데이터”에 잘 맞습니다.

2) 튜플로 고정 구조 표현

>>> server = ("api-01", "10.0.0.12", 443)
>>> name, ip, port = server
>>> print(name, ip, port)
api-01 10.0.0.12 443

튜플은 좌표 (x, y), DB 레코드의 일부 스냅샷, 설정값 묶음처럼 의미가 고정된 묶음을 표현할 때 좋습니다.

3) 패킹/언패킹으로 코드 간결화

>>> a, b = 5, 9
>>> a, b = b, a
>>> a, b
(9, 5)

>>> user = ("kim", 29, "premium")
>>> user_id, age, grade = user
>>> user_id
'kim'

임시 변수 없이 값 교환이 가능하고, 함수 반환값 처리도 깔끔해집니다.

4) 실무형 예제: 일별 매출 집계

>>> sales = [120000, 98000, 143000, 87000, 156000]
>>> total = sum(sales)
>>> avg = total / len(sales)
>>> max_day = sales.index(max(sales)) + 1
>>> print(f"총매출: {total:,}원")
>>> print(f"평균매출: {avg:,.0f}원")
>>> print(f"최고 매출일: {max_day}일차")
총매출: 604,000원
평균매출: 120,800원
최고 매출일: 5일차

집계 대상이 계속 추가/수정되는 상황에서는 리스트가 자연스럽고, 결과를 요약한 고정 레코드는 튜플로 반환하면 의도를 분리하기 좋습니다.


자주 하는 실수

실수 1) 리스트 복사 착각(얕은 복사 이슈)

>>> a = [1, 2, 3]
>>> b = a
>>> b.append(4)
>>> a
[1, 2, 3, 4]

b = a는 복사가 아니라 같은 객체를 가리키는 참조 대입입니다. 독립된 사본이 필요하면 a.copy() 또는 a[:]를 사용하세요.

실수 2) 요소 1개짜리 튜플 문법 누락

>>> one = (10)
>>> type(one)
<class 'int'>

>>> one_tuple = (10,)
>>> type(one_tuple)
<class 'tuple'>

튜플 한 개 원소는 반드시 쉼표가 필요합니다.

실수 3) 변경해야 할 데이터를 튜플로 설계

초기에 “안 바뀔 것 같다”는 이유로 튜플을 선택했다가, 요구사항 변경으로 값 업데이트가 필요해지면 구조 변경 비용이 커집니다. 변경 가능성이 조금이라도 있으면 리스트로 시작하고, 안정화된 뒤 튜플로 고정하는 편이 실무적으로 안전합니다.

실수 4) 리스트 메서드 반환값 오해

>>> nums = [3, 1, 2]
>>> result = nums.sort()
>>> result
>>> print(result)
None
>>> nums
[1, 2, 3]

list.sort()는 리스트 자체를 정렬하고 None을 반환합니다. 새 정렬 결과가 필요하면 sorted(nums)를 사용하세요.


오늘의 결론

리스트와 튜플의 선택 기준은 문법이 아니라 데이터의 생명주기입니다.

  1. 값이 바뀔 가능성이 있으면 리스트를 사용한다.
  2. 의미적으로 고정된 레코드라면 튜플을 사용한다.
  3. 리스트 참조/복사 차이를 이해해야 예기치 않은 데이터 오염을 막는다.
  4. 언패킹을 적극 활용하면 코드 가독성과 유지보수성이 함께 좋아진다.

이 원칙만 지켜도 이후에 배울 함수 인자 설계, 딕셔너리 조합, 파일 파싱 코드가 훨씬 안정적으로 작성됩니다.


연습문제

  1. 리스트 scores = [72, 88, 95, 64, 83]에서 80점 이상 점수만 새로운 리스트로 만들어 출력해보세요.
  2. 튜플 server = ("db-01", "192.168.0.10", 5432)를 언패킹해 각각 변수에 담고, f-string으로 한 줄 요약을 출력해보세요.
  3. 리스트 items = ["A", "B", "C"]를 복사해 items2를 만든 뒤 items2에만 "D"를 추가했을 때, 원본 items가 바뀌지 않도록 코드를 작성해보세요.

이전 강의 정답 (05강 연습문제)

  1. 1부터 10까지 출력하되 7 건너뛰기 (continue)
>>> n = 1
>>> while n <= 10:
...     if n == 7:
...         n += 1
...         continue
...     print(n)
...     n += 1
...
1
2
3
4
5
6
8
9
10
  1. 비밀번호 최대 3회 시도, 성공 시 즉시 종료
>>> correct = "python100"
>>> tries = 0
>>> success = False
>>> while tries < 3:
...     pw = input("비밀번호: ").strip()
...     tries += 1
...     if pw == correct:
...         print("성공")
...         success = True
...         break
...
비밀번호: 1234
비밀번호: qwer
비밀번호: python100
성공
>>> if not success:
...     print("실패")
...
  1. temps에서 25도 이상만 출력
>>> temps = [18, 21, 19, 25, 30, 22]
>>> i = 0
>>> while i < len(temps):
...     if temps[i] >= 25:
...         print(temps[i])
...     i += 1
...
25
30

실습 환경/재현 정보

  • 실행 환경: conda env python100 (Python 3.11.14)