튜플
1. 튜플(Tuple)이란?
튜플은 파이썬에서 제공하는 불변(immutable)하고 순서가 있는 시퀀스 자료형입니다. 리스트와 유사하게 여러 개의 데이터를 하나로 묶어서 사용할 수 있지만, 한 번 생성된 튜플은 내부의 값 변경이 불가능합니다.
튜플은 불변이므로 리스트보다 메모리 효율적이고 처리 속도가 빠릅니다. 변경되면 안 되는 데이터나 딕셔너리의 키로 사용할 때 적합합니다.그럼 튜플은 언제 쓰여야 할까요?
학번이나 이름, 주민등록번호와 같이 변경되면 안 되는 정보 등에 사용해야 할 것입니다. 프로그래머가 이러한 이해 없이 마음대로 값을 변경하려고 할 때 튜플은 이를 방지해줍니다.
1.1 튜플 생성
튜플은 소괄호()를 사용하고 그 안에 쉼표,로 구분된 데이터들을 넣으면 됩니다.
x = (1, 2, 3)
y = ('apple', 'banana', 'cherry')
리스트와 마찬가지로 튜플 내부에도 다양한 데이터 타입을 포함할 수 있습니다. 심지어 튜플 내부에 리스트나 또 다른 튜플을 넣는 것도 가능합니다!
튜플 안에 다양한 타입의 데이터를 함께 저장할 수 있어요.
z = (1, 'apple', 2.5, ['a', 'b'], (1, 2))
변경가능한 자료형을 튜플과 같은 변경 불가능한 자료형 안에 넣는 것은 값에 변경이 이뤄질 수 있기 때문에 좋은 선택은 아닙니다.
x = [10, 20, 30]
y = (1, 2, x)
x[0] = 1000
y # 출력: (1, 2, [1000, 20, 30])
위와 같은 이유로 리스트나 튜플에 값은 주로 그 형태를 맞춰 값을 넣어줍니다. 아래처럼 여러 개의 자료형을 같이 사용하는 경우는 드물다고 할 수 있습니다.
test = ('hello world', [1, 2, 3], 1, 10, 10.1, (1, 2, 3))
단일 요소를 생성을 할 때에는 콤마를 넣어주세요. 그렇지 않으면 아래와 같이 다른 자료형이 될 수 있습니다.
t1 = () # tuple
t2 = (0,) # tuple 단일 값의 튜플을 사용할때 꼭 콤마를 넣어주세요!
t3 = (0) # int
t4 = (0.1) # float
print(type(t1))
print(type(t2))
print(type(t3))
print(type(t4))
1.2 튜플의 특징
1.2.1 튜플은 변경이 불가능하다(immutable)
처음에 언급했다시피 튜플은 한 번 생성하면 그 안의 참조 값을 바꿀 수 없습니다. 여기서 참조 값은 가리키고 있는 값입니다. 위에서 살펴본 것처럼 안에 변경 가능한 자료형을 넣으면 값에 변경은 될 수 있습니다.
a = (1, 2, 3, 4, 5)
# a[0] = 10000 이렇게 하면 에러가 발생합니다!
# 튜플 오브젝트는 새로운 아이템의 할당을 허용하지 않습니다. 라는 오류
1.2.2 튜플을 왜 사용할까?
"그럼 튜플을 왜 사용하나요?"라고 의문을 가질 수 있으실 것 같습니다. 때때로 변경되면 안 되는 데이터를 보호하거나, 프로그램 실행 중에 값이 바뀌면 안 되는 경우가 있어요. 그런 상황에서 튜플을 사용하면 데이터의 안전성을 높일 수 있습니다.
또한, 튜플은 리스트에 비해 처리 속도가 조금 더 빠르기도 합니다. 그래서 단순히 데이터를 읽기만 할 때는 튜플을 사용하는 것이 더 효율적일 수 있습니다.
2. 튜플의 연산
튜플도 리스트처럼 다양한 연산을 지원합니다. 튜플은 변경이 불가능한 자료형이지만, 새로운 튜플을 생성하거나 다른 튜플과 합치는 등의 연산은 가능합니다.
2.1 덧셈과 곱셈 연산
덧셈은 두 튜플을 연결합니다.
tuple1 = (1, 2, 3)
tuple2 = (4, 5, 6)
tuple3 = tuple1 + tuple2
print(tuple3) # 출력: (1, 2, 3, 4, 5, 6)
곱셈은 튜플을 여러번 반복합니다.
tuple1 = (1, 2, 3)
tuple2 = tuple1 * 3
print(tuple2) # 출력: (1, 2, 3, 1, 2, 3, 1, 2, 3)
2.2 튜플 인덱싱
튜플도 순서가 있는 시퀀스 자료형이기 때문에 인덱싱을 통해 각 항목에 접근할 수 있습니다.
t = (1, 2, 3, 4, 5)
print(t[0]) # 출력: 1
2.3 튜플 슬라이싱
튜플도 리스트처럼 슬라이싱을 사용하여 부분적인 값을 추출할 수 있습니다.
t = (1, 2, 3, 4, 5)
print(t[1:4]) # 출력: (2, 3, 4)
슬라이싱의 속성은 리스트에서 설명한 내용과 동일하기 때문에 생략하겠습니다.
3. 튜플의 구조 및 특징
튜플은 리스트와 유사한 점이 많지만, 몇 가지 중요한 차이점이 있습니다. 튜플은 변경 불가능한(immutable) 데이터 구조입니다. 이 의미는 튜플의 원소나 크기를 변경할 수 없다는 것입니다.
3.1 메모리 구조
그러나 튜플의 메모리 구조는 리스트와 상당히 유사합니다. 튜플 역시 객체의 참조를 저장하는 컨테이너입니다. 따라서 튜플의 각 요소도 실제 데이터 값을 직접 저장하는 것이 아니라, 해당 객체를 참조하는 주소를 저장합니다.
다음과 같이 튜플을 생성해봅시다.
my_tuple = (1, 2, 'apple', 3.14)
이 튜플의 메모리 구조는 다음과 같이 설명될 수 있습니다:
1,2,'apple',3.14는 각각 다른 메모리 위치에 저장된 객체입니다.my_tuple은 이러한 객체들의 참조(즉, 메모리 주소)를 저장하는 배열입니다.
3.2 불변성
튜플의 가장 큰 특징 중 하나는 불변성(immutable) 입니다. 이는 한 번 생성된 튜플의 내용(크기 및 원소)을 변경할 수 없다는 것을 의미합니다.
- 메모리 효율성: 튜플의 불변성 덕분에, 일반적으로 리스트보다 메모리 사용이 더 효율적입니다. 리스트는 원소의 추가나 삭제를 고려해 추가적인 메모리를 예약할 수 있습니다. 튜플은 그 크기가 고정되어 있으므로 추가적인 메모리 할당은 필요하지 않습니다.
- 해시 가능: 튜플의 불변성으로 인해 원소들이 모두 해시 가능할 경우 튜플도 해시 가능합니다. 즉, 튜플을 딕셔너리의 키로 사용할 수 있다는 것을 의미합니다.
- 보안: 데이터의 무결성을 유지해야 하는 경우나 데이터가 변경되어서는 안되는 경우에 튜플을 사용하면 좋습니다. 튜플의 불변성은 데이터 변경을 방지해 줍니다.
4. 튜플의 메서드
리스트에서 메서드를 확인해 보았듯이 튜플 메서드와 속성을 확인해보겠습니다.
print(dir(tuple))
# 출력
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '...중략', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
튜플은 변경이 불가능하기 때문에 리스트에 비해 제공하는 메서드의 수가 매우 제한적입니다. 그럼에도 불구하고 두 가지 주요 메서드를 제공하고 있습니다.
4.1 count()
튜플 내에서 특정 값이 나타나는 횟수를 반환합니다.
tuple1 = (1, 2, 3, 4, 3, 5)
print(tuple1.count(3)) # 출력: 2
4.2 index()
특정 값이 튜플 내에서 처음으로 나타나는 위치의 인덱스를 반환합니다.
tuple1 = (1, 2, 3, 4, 3, 5)
print(tuple1.index(3)) # 출력: 2
이처럼 튜플은 변경 불가능한 특성 때문에 메서드는 제한적이지만, 데이터의 안정성이나 처리 속도 측면에서 장점이 있습니다. 따라서 프로그램의 특정 부분에서는 튜플을 사용하는 것이 더 유리할 수 있습니다.