본문으로 건너뛰기
김신건의 로그

[Python] tuple: 불변 시퀀스와 NamedTuple

· 수정 · 📖 약 1분 · 413자/단어 #python #tuple #sequence #immutable #basics
python tuple, 파이썬 튜플, namedtuple, tuple unpacking

정의

tuple불변(immutable) 시퀀스다. list와 거의 같은 API를 가지나 생성 후 변경 불가하며, 그 덕에 dict 키나 set 원소로 사용 가능하다(해시 가능). 함수의 다중 반환값, 좌표·레코드 같은 고정 구조에 흔히 쓰인다.

생성

empty = ()
single = (1,)        # 콤마 필수! (1)는 그냥 괄호 묶인 표현식
pair = (1, 2)
triple = 1, 2, 3     # 괄호 없이도 됨 (tuple packing)
from_iter = tuple([1, 2, 3])

함정: (1)int, (1,)tuple.

python
print(type((1)))
print(type((1,)))
print(type(()))
결과
<class 'int'>
<class 'tuple'>
<class 'tuple'>

불변성

t = (1, 2, 3)
t[0] = 99   # TypeError: 'tuple' object does not support item assignment

하지만 내부에 가변 객체가 있으면 그 객체는 변경 가능하다.

t = ([1, 2], [3, 4])
t[0].append(99)        # 리스트 자체는 변경 가능
print(t)               # ([1, 2, 99], [3, 4])

따라서 “tuple이 hashable이다”는 항상 참이 아니다. 내부에 list가 들어 있으면 hash(t)TypeError.

언패킹 (Tuple Unpacking)

가장 강력하고 흔히 쓰이는 기능.

python
a, b = 1, 2
print(a, b)

# 변수 교환
a, b = b, a
print(a, b)

# 다중 반환값
def minmax(xs):
  return min(xs), max(xs)

lo, hi = minmax([3, 1, 4, 1, 5])
print(lo, hi)

# 스타 언패킹
first, *rest = (1, 2, 3, 4)
print(first, rest)
결과
1 2
2 1
1 5
1 [2, 3, 4]

메서드 (불변이라 단 2개)

t = (1, 2, 3, 2, 1)
t.count(2)     # 2
t.index(3)     # 2

읽기 연산(len, in, 슬라이스, min/max/sum)은 list와 동일.

NamedTuple: 이름 있는 필드

collections.namedtuple 또는 typing.NamedTuple로 필드명을 부여한다. 작은 데이터 클래스가 필요할 때 dataclass보다 가볍다.

python
from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p)
print(p.x, p.y)
print(p[0], p[1])    # 인덱스 접근도 가능
print(p._asdict())   # OrderedDict 변환

# 기존 값으로 새 인스턴스 (불변)
q = p._replace(x=99)
print(q)
결과
Point(x=3, y=4)
3 4
3 4
{'x': 3, 'y': 4}
Point(x=99, y=4)

타입 힌트가 필요하면 typing.NamedTuple:

from typing import NamedTuple

class User(NamedTuple):
    id: int
    name: str
    age: int = 0    # 기본값

u = User(1, "Alice")

tuple vs list vs dataclass vs NamedTuple

타입가변해시필드명메모리용도
tupleXOX최소고정 레코드, 다중 반환
listOXX보통동적 컬렉션
namedtupleXOO최소+가벼운 불변 레코드
dataclass(frozen=True)XOO보통메서드/검증이 필요한 불변 데이터
dataclassOXO보통일반 데이터 클래스

hashable 활용

seen = set()
for x, y in points:
    if (x, y) in seen:
        continue
    seen.add((x, y))

# dict 키
cache = {}
def fib(n):
    if n in cache:
        return cache[n]
    cache[n] = fib(n - 1) + fib(n - 2) if n > 1 else n
    return cache[n]

# 좌표를 dict 키로
grid = {(0, 0): "start", (1, 1): "wall"}

함수 리턴값 관용구

Python 함수는 사실상 항상 튜플을 반환한다(다중 값 = 튜플).

def stats(xs):
    return min(xs), max(xs), sum(xs) / len(xs)

lo, hi, avg = stats([1, 2, 3, 4, 5])
result = stats([1, 2, 3])   # (1, 3, 2.0) 튜플

성능

  • 메모리: tuple은 list보다 약 30% 작음 (over-allocation 없음).
  • 생성: 컴파일 타임 상수 튜플은 LOAD_CONST로 즉시 적재(list는 매번 생성).
import dis
dis.dis("x = (1, 2, 3)")    # LOAD_CONST  (1, 2, 3)
dis.dis("x = [1, 2, 3]")    # BUILD_LIST  (3개 로드 + 빌드)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기