Python Tuple과 List: 유사점과 차이점 설명
이 안내서는 파이썬 튜플과 리스트의 공통점 및 차이점을 심층적으로 다룹니다. 또한 튜플을 사용해야 하는 특정 상황에 대한 이해를 돕습니다.
리스트와 튜플은 파이썬에서 제공하는 기본 데이터 구조로, 여러 요소들의 집합을 저장하는 데 유용합니다.
인덱싱, 슬라이싱, 다양한 데이터 타입 포함 등 여러 면에서 튜플과 리스트는 비슷한 기능을 제공하는 것처럼 보일 수 있습니다. 따라서, 이 두 구조의 유사점과 차이점을 명확히 이해하는 것은 데이터 구조를 선택하는 데 매우 중요합니다.
이제 함께 자세히 알아보겠습니다.
👩🏽💻 파이썬 REPL을 실행하거나 koreantech.org의 온라인 편집기를 사용하여 이 튜토리얼을 따라 실습해 볼 수 있습니다.
파이썬 튜플 vs 리스트: 주요 유사점
먼저, 리스트와 튜플의 공통점을 살펴보겠습니다. 이해를 돕기 위해 실제 예시를 함께 제시합니다.
#1. 파이썬에서 반복 가능한 객체
파이썬에서 리스트는 대괄호([])로 묶인 반면, 튜플은 괄호(())로 묶습니다. 쉼표로 구분된 값들을 괄호 없이 나열하여 튜플을 만들 수도 있습니다.
이 두 구조 모두 반복 가능하며, for 루프를 사용하여 요소들을 순회할 수 있습니다.
아래 코드 예시는 리스트를 반복하는 방법을 보여줍니다.
nums = [2, 6, 7, 10]
print(f"nums의 타입은 {type(nums)} 입니다")
for num in nums:
print(num)
# 출력
nums의 타입은 <class 'list'> 입니다
2
6
7
10
다음은 for 루프를 사용하여 튜플을 반복하는 예시입니다.
nums = (2, 6, 7, 10)
# 참고: nums = 2, 6, 7, 10 역시 유효한 튜플입니다. 필요하다면 직접 확인해보세요!
print(f"nums의 타입은 {type(nums)} 입니다")
for num in nums:
print(num)
# 출력
nums의 타입은 <class 'tuple'> 입니다
2
6
7
10
#2. 다른 시퀀스로부터 생성 가능
리스트와 튜플의 또 다른 공통점은 문자열과 같은 기존 시퀀스를 기반으로 생성할 수 있다는 점입니다.
sample_str = "코딩!"
다음 예시는 문자열의 각 문자를 요소로 가지는 리스트를 만드는 방법을 보여줍니다.
list_from_str = list(sample_str) print(list_from_str) # 출력 ['코', '딩', '!']
마찬가지로, tuple(sequence) 함수를 사용하여 문자열이나 다른 시퀀스로부터 튜플을 생성할 수 있습니다. 아래 예시를 확인하세요.
tuple_from_str = tuple(sample_str)
print(tuple_from_str)
# 출력
('코', '딩', '!')
#3. 인덱싱 및 슬라이싱 지원
파이썬은 첫 번째 요소가 인덱스 0, 두 번째 요소가 인덱스 1에 할당되는 제로 인덱싱을 지원합니다. 또한 마지막 요소가 -1, 마지막에서 두 번째 요소가 -2로 참조되는 음수 인덱싱도 지원합니다.
list_from_str = ['코', '딩', '!'] print(list_from_str[1]) # 딩
인덱스 -2에 해당하는 요소는 마지막에서 두 번째 요소인 '딩'입니다.
tuple_from_str = ('코', '딩', '!')
print(tuple_from_str[-2])
# 딩
리스트나 튜플의 일부분만 사용해야 할 때는 슬라이싱을 활용할 수 있습니다. 리스트[start:end]는 인덱스 start부터 end-1까지의 요소를 포함하는 새로운 리스트를 반환합니다. start 값의 기본값은 0이며, end 값의 기본값은 시퀀스의 마지막 요소입니다.
튜플 또한 동일한 문법으로 슬라이싱할 수 있습니다. 앞에서 만든 리스트와 튜플을 슬라이싱하여 예시를 보겠습니다.
list_from_str = ['코', '딩', '!'] print(list_from_str[0:2]) ['코', '딩']
start 및 end 값 외에도 step 값을 지정할 수 있습니다. 튜플[start:end:step]은 start부터 end까지 step 간격으로 튜플의 슬라이스를 반환합니다.
tuple_from_str = ('코', '딩', '!')
print(tuple_from_str[::2])
('코', '!')
여기에서는 step 값을 2로 설정했으므로, 슬라이스에는 모든 두 번째 요소가 포함됩니다.
#4. 다양한 데이터 타입의 조합
지금까지 살펴본 예시에서는 리스트와 튜플의 모든 요소가 같은 데이터 타입이었지만, 하나의 리스트나 튜플 안에 여러 데이터 타입의 값을 저장하는 것도 가능합니다.
아래의 student_list 예시에서는 학생의 이름을 문자열, 나이를 정수, 점수를 부동 소수점으로 저장합니다.
student_list = ["철수", 22, 96.5]
for item in student_list:
print(f"{item}의 타입은 {type(item)} 입니다")
# 출력
철수의 타입은 <class 'str'> 입니다
22의 타입은 <class 'int'> 입니다
96.5의 타입은 <class 'float'> 입니다
튜플에서도 비슷한 예시를 만들 수 있습니다.
student_tuple = ("영희", 23, 99.5)
for item in student_tuple:
print(f"{item}의 타입은 {type(item)} 입니다")
# 출력
영희의 타입은 <class 'str'> 입니다
23의 타입은 <class 'int'> 입니다
99.5의 타입은 <class 'float'> 입니다
#5. 멤버십 테스트 지원
리스트와 튜플 모두 특정 요소의 존재 여부를 확인하는 멤버십 테스트를 지원합니다. in 연산자를 사용하여 특정 요소가 리스트나 튜플에 포함되어 있는지 확인할 수 있습니다.
표현식 item in iterable은 iterable에 item이 포함되어 있으면 True를 반환하고, 그렇지 않으면 False를 반환합니다.
"민수" in student_list # False "영희" in student_tuple # True
지금까지 파이썬 리스트와 튜플의 유사점을 살펴보았습니다. 다음으로는 두 데이터 구조의 주요 차이점을 알아볼 차례입니다.
파이썬 튜플 vs 리스트: 주요 차이점
#1. 리스트의 가변성 및 튜플의 불변성
파이썬에서 리스트와 튜플의 가장 큰 차이점은 튜플이 불변(immutable)하다는 점입니다. 즉, 튜플을 생성한 후에는 그 내용을 변경할 수 없습니다.
▶️ 예시:
tuple1 = ("Java", "Python", "C++")
tuple1[0] = "Rust"
# 출력
----> 2 tuple1[0] = "Rust"
TypeError: 'tuple' 객체는 항목 할당을 지원하지 않습니다
리스트는 가변(mutable) 데이터 구조이므로, 다음 코드처럼 특정 인덱스의 요소를 변경하여 수정할 수 있습니다.
list1 = ["Java", "Python", "C++"] list1[0] = "Rust" print(list1) # 출력 ['Rust', 'Python', 'C++']
#2. 가변 길이 리스트와 고정 길이 튜플
파이썬 리스트는 가변 길이 데이터 구조입니다.
다음과 같은 작업을 수행할 수 있습니다.
- 리스트의 끝에 요소 추가
- 다른 리스트의 요소를 현재 리스트의 끝에 추가
- 특정 인덱스의 요소 제거
list1 = [2, 3, 4, 5] # 끝에 요소 추가 list1.append(9) print(list1) # list2의 요소를 list1 끝에 추가 list2 = [0, 7] list1.extend(list2) print(list1) # list1에서 요소 제거 list1.pop(0) print(list1)
▶️ 위 코드의 출력 결과는 다음과 같습니다.
# 출력 [2, 3, 4, 5, 9] [2, 3, 4, 5, 9, 0, 7] [3, 4, 5, 9, 0, 7]
튜플은 고정 길이 데이터 구조입니다. 따라서 기존 튜플에서 요소를 추가하거나 제거할 수 없습니다. 하지만 튜플 변수에 다른 요소를 할당하여 튜플을 재정의할 수는 있습니다.
tuple1 = (2, 4, 6, 8) tuple1 = (1, 8, 9) print(tuple1) # 출력 (1, 8, 9)
#3. 메모리 크기
이전 섹션에서 배운 내용을 바탕으로 생각해 봅시다. 리스트는 가변 길이 데이터 구조입니다.
리스트를 처음 정의할 때, 메모리에 특정 크기가 할당됩니다. 이제 append()나 extend() 메서드를 사용하여 리스트를 수정할 때, 추가된 요소를 저장하기 위한 추가 메모리가 할당되어야 합니다. 이러한 할당은 거의 항상 추가하는 항목 수보다 더 크게 수행됩니다.
따라서 리스트는 요소의 수와 할당된 공간을 추적해야 합니다. 또한 리스트는 가변 길이이므로, 각 요소의 주소를 가리키는 포인터를 가지고 있습니다. 결과적으로, 길이가 k인 리스트는 동일한 k개의 요소를 가진 튜플보다 더 많은 메모리를 차지합니다.
다음은 간단한 그림입니다.

파이썬 객체에 내장된 sys 모듈의 getsizeof() 메서드를 사용하여 메모리에 있는 객체의 크기를 확인할 수 있습니다.
import sys
list1 = [4, 5, 9, 14]
list_size = sys.getsizeof(list1)
print(f"리스트 크기: {list_size}")
tuple1 = (4, 5, 9, 14)
tuple_size = sys.getsizeof(tuple1)
print(f"튜플 크기: {tuple_size}")
아래 출력에서 확인할 수 있듯이, 리스트는 같은 수와 값을 가진 요소의 튜플보다 더 많은 메모리를 차지합니다.
# 출력 리스트 크기: 104 튜플 크기: 88

파이썬 튜플은 언제 사용해야 할까요?
파이썬 리스트와 튜플의 차이점과 유사점을 통해, 변경 가능한 컬렉션이 필요한 경우 리스트를 사용해야 한다는 것을 알 수 있습니다.
하지만 튜플은 언제 사용해야 할까요?
이 섹션에서 자세히 살펴보겠습니다.
#1. 읽기 전용 컬렉션
컬렉션을 변경할 수 없도록 하려면 항상 튜플로 정의해야 합니다. 예를 들어, 색상 음영에 해당하는 RGB 값 (243, 55, 103)을 담는 튜플을 color 변수에 저장했다고 가정해 보겠습니다. 색상을 튜플로 정의하면 값을 수정할 수 없습니다.
컬렉션이 읽기 전용이어야 할 때, 즉 프로그램 실행 중에 값을 변경해서는 안 되는 경우 튜플을 사용하는 것을 고려해야 합니다. 이렇게 하면 의도하지 않은 값 변경을 방지할 수 있습니다.
#2. 딕셔너리 키
예를 들어, key_list의 항목을 키로 사용하여 딕셔너리를 생성한다고 가정해 봅시다. dict.fromkeys() 메서드를 사용하여 리스트로부터 딕셔너리를 생성할 수 있습니다.
key_list = list("ABCD")
dict.fromkeys(key_list)
{'A': None, 'B': None, 'C': None, 'D': None}
딕셔너리를 만들기 전에, 첫 번째 요소(인덱스 0)를 'D'로 변경하여 리스트를 수정한다고 가정해 봅시다.
이제 딕셔너리의 키 'A'는 어떻게 될까요?
key_list에서 딕셔너리를 생성한 후, 'A' 키에 해당하는 값에 접근하려고 하면 KeyError가 발생합니다.
key_list[0] = 'D' dict.fromkeys(key_list)['A'] --------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-31-c90392acc2cf> in <module>() ----> 1 dict.fromkeys(key_list)['A'] KeyError: 'A'
딕셔너리의 키는 고유해야 합니다. 따라서 두 번째 'D'를 키로 가질 수 없습니다.
dict.fromkeys(key_list)
{'B': None, 'C': None, 'D': None} # A는 더 이상 키가 아닙니다.
반면에 튜플을 사용하면 이러한 수정이 불가능하므로 오류 발생 가능성을 줄일 수 있습니다. 따라서 튜플의 요소를 키로 사용하여 딕셔너리를 만드는 것이 좋습니다.
key_tuple = tuple("ABCD")
dict.fromkeys(key_tuple)
{'A': None, 'B': None, 'C': None, 'D': None}
key_tuple[0] = 'D'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-2cecbefa7db2> in <module>()
----> 1 key_tuple[0] = 'D'
TypeError: 'tuple' 객체는 항목 할당을 지원하지 않습니다
#3. 함수 인자
튜플의 불변성은 함수 인자로 전달하기에도 적합하게 만듭니다.
길이, 너비, 높이와 같은 치수가 주어졌을 때 직육면체의 부피를 반환하는 다음 함수 find_volume()을 고려해 보겠습니다.
def find_volume(dimensions):
l, b, h = dimensions
return l * b * h
차원들이 리스트에 저장되어 있다고 가정하고, dimensions 리스트를 인자로 사용하여 find_volume() 함수를 호출하면 부피를 반환합니다.
dimensions = [2, 8, 5] find_volume(dimensions) 80
리스트에 저장된 치수는 언제든지 변경할 수 있습니다.
dimensions = [20, 8, 5] find_volume(dimensions) 800
그러나 때로는 값을 일정하게 유지하고 수정에 저항해야 할 경우가 있습니다. 이럴 때 인자를 튜플에 저장하고 함수 호출에 사용하는 것을 고려해야 합니다.
#4. 함수의 반환 값
파이썬에서 함수의 반환 값으로 튜플을 자주 만나게 됩니다. 함수가 여러 개의 값을 반환하면 파이썬은 암시적으로 이 값을 튜플로 반환합니다.
다음 함수 return_even()을 고려해 봅시다.
def return_even(num):
even = [i for i in range(num) if (i % 2 == 0)]
return even, len(even)
- 인수로 숫자 num을 받습니다.
- [0, num) 범위의 짝수 리스트와 리스트의 길이를 반환합니다.
num 값을 20으로 설정하고 함수를 호출해 보겠습니다.
num = 20
return_even() 함수를 호출하면 두 개의 값이 튜플 형태로 반환됩니다. type() 함수를 사용하여 반환 값이 튜플임을 확인할 수 있습니다.
type(return_even(num)) # <class 'tuple'>
반환 값을 출력하면 첫 번째 요소로 짝수 리스트가 있고, 두 번째 요소로 리스트의 길이가 있는 튜플임을 확인할 수 있습니다.
print(return_even(num)) ([0, 2, 4, 6, 8, 10, 12, 14, 16, 18], 10)
튜플에 두 개의 요소가 있으므로, 다음과 같이 두 개의 변수로 언패킹할 수 있습니다.
even_nums, count = return_even(num) print(even_nums) print(count) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 10
결론
이 튜토리얼을 통해 파이썬 튜플과 리스트에 대한 포괄적인 비교를 할 수 있었기를 바랍니다.
빠른 요약을 통해 튜토리얼을 마무리하겠습니다.
- 리스트와 튜플은 파이썬의 내장 데이터 구조입니다.
- 유사점: 반복 가능한 객체, 인덱싱 및 슬라이싱 지원, 다양한 데이터 타입 포함, 멤버십 테스트를 위한 연산자.
- 주요 차이점: 리스트는 가변적이며 튜플은 불변적입니다.
- 기타 차이점: 튜플의 고정 길이와 리스트의 가변 길이, 튜플의 작은 메모리 크기.
- 튜플을 언제 사용해야 할까요? 변경 불가능한 컬렉션, 딕셔너리 키, 함수 인자 등으로 사용합니다.
다음으로 파이썬 프로젝트를 통해 연습하고 더 많은 것을 배워보세요. 또는 파이썬 리스트에서 중복 항목을 제거하는 방법을 배워보세요. 즐거운 학습 시간 되세요! 그럼, 해피 코딩! 👩🏽💻