튜플은 순서가 있지만 만든 뒤 원소를 바꿀 수 없는 시퀀스야. 괄호보다 쉼표가 핵심이라 원소 하나짜리 튜플은 (value,)처럼 써야 해. 함수가 여러 값을 돌려주는 것처럼 보일 때도 실제로는 튜플을 돌려주고 언패킹하는 경우가 많아.
모양을 한 번에 풀어 받기
a, b = pair처럼 위치에 맞춰 이름을 붙이고, 별표 이름으로 가운데 여러 값을 받을 수 있어. 순서와 개수가 계약인 작은 레코드에 잘 어울리지만, 필드가 많아지면 이름이 있는 형태가 더 안전해.
불변과 해시 가능은 같은 말이 아니야
튜플 자체는 원소를 갈아 끼울 수 없지만 안에 리스트가 있으면 그 리스트는 바뀔 수 있어. 딕셔너리 키나 집합 원소가 되려면 튜플 안의 모든 값도 해시 가능해야 해.
namedtuple로 위치에 이름 붙이기
namedtuple은 튜플의 작은 크기와 언패킹을 유지하면서 point.x처럼 필드 이름으로 읽게 해. 기본값·검증·행동이 많아지면 dataclass가 더 알맞아.
Code
튜플과 원소 하나짜리 튜플·python
# 모두 tuple — 콤마가 진짜 연산자
empty = ()
single = (1,) # 끝 콤마 필수
pair = 1, 2 # 괄호 옵션
triple = (1, 2, 3)
mixed = "a", 1, [2, 3] # tuple 안에 뭐든
# 끝 콤마 없으면 그냥 괄호 친 식
not_a_tuple = (1)
print(type(not_a_tuple)) # <class 'int'>
print(type(single)) # <class 'tuple'>
# tuple() 생성자 — 어떤 iterable 도
t = tuple("abc")
print(t) # ('a', 'b', 'c')
언패킹과 별표로 여러 값 받기·python
# 다중 할당
x, y, z = 1, 2, 3
# swap
a, b = 10, 20
a, b = b, a
print(a, b) # 20 10
# 여러 값 반환하는 함수도 사실 tuple 반환
def divmod_(a, b):
return a // b, a % b
q, r = divmod_(17, 5)
print(q, r) # 3 2
# star-unpacking — 나머지 잡기
first, *middle, last = [1, 2, 3, 4, 5]
print(first, middle, last) # 1 [2, 3, 4] 5
해시 가능한 튜플만 키가 된다·python
# hashable 한 것들의 tuple 은 hashable
grid = {}
grid[(0, 0)] = "start"
grid[(3, 4)] = "goal"
print(grid[(3, 4)]) # 'goal'
# list 가 들어간 tuple 은 hashable 하지 않음
bad_key = (1, [2, 3])
try:
grid[bad_key] = "oops"
except TypeError as e:
print("실패:", e) # unhashable type: 'list'
튜플 안의 가변 객체·python
t = ([1, 2], 3)
# t[0] 자체는 재할당 불가
try:
t[0] = [99]
except TypeError as e:
print(e) # 'tuple' object does not support item assignment
# 근데 t[0] 이 가리키는 객체는 mutable
t[0].append(99)
print(t) # ([1, 2, 99], 3)
# 그래서 이 tuple 은 hashable 도 아님 — 안의 list 가 깨
try:
hash(t)
except TypeError as e:
print(e) # unhashable type: 'list'
필드 이름이 있는 namedtuple·python
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y) # 3 4 — 이름 접근
print(p[0], p[1]) # 3 4 — 인덱싱도 됨
x, y = p # unpacking 도 됨
print(x, y) # 3 4
# 불변
try:
p.x = 99
except AttributeError as e:
print(e) # can't set attribute
# _replace — 새 namedtuple 반환
p2 = p._replace(x=10)
print(p2) # Point(x=10, y=4)