본문 바로가기

프로그래밍/Python

파이썬(Python) 기초 Step 4. 튜플(Tuple)

튜플(Tuple)은 리스트(List)와 매우 비슷한 데이터 타입입니다. 때문에 많은 사람들이 이 둘의 차이점은 알지만 어떠한 경우에 사용해야 하는 지에 대해서 헷갈려하는 경우가 많습니다. 그래서 튜플과 리스트의 차이점을 알아보고 언제 튜플을 사용해야 하는 지에 대해서 알아보도록 하겠습니다. 


○ 튜플을 정의하는 방법

리스트를 정의할 때에는 브라켓([ ])을 사용하여 정의하지만, 튜플은 괄호"( )"를 사용하여 정의합니다. 튜플을 정의해보면 예시 1)의 결과 (1)과 같습니다. 방금 정의한 튜플의 데이터 타입을 확인해보면 tuple이라는 것을 알 수 있습니다(예시 1)의 결과 (2) 참조). 또한 예시 2)의 결과 (1)과 같이 괄호를 생략하여 정의할 수도 있습니다. 이 역시 데이터 타입을 확인해보면 tuple이라는 것을 알 수 있습니다(예시 2)의 결과 (2) 참조).

예시 1)

tuple_1 = (1, 2, 3)
tuple_1
type(tuple_1)

결과 (1) ▷ (1, 2, 3)
결과 (2) ▷ tuple 
예시 2)

tuple_2 = 1, 2, 3
tuple_2
type(tuple_2)

결과 (1) ▷ (1, 2, 3)
결과 (2) ▷ tuple 

튜플을 정의할 때에는 주의해야할 점이 있습니다. 튜플에 정의하고자 하는 데이터가 한 개 일때는 뒤에 데이터가 존재하지 않아도 반드시 콤마( , )를 입력해야 합니다. 만약 콤마를 입력하지 않고 튜플을 정의한다면 예시 3)의 결과 (1)과 같이 괄호가 생성되지 않으며, 예시 3)의 결과 (2)와 같이 데이터 타입이 string으로 생성됩니다. 

예시 3)

tuple_3 = ('C')
tuple_3
type(tuple_3)

결과 (1) ▷ 'C'
결과 (2) ▷ str

이번에는 콤마를 입력하여 데이터가 한 개인 튜플을 정의해보도록 하겠습니다. 예시 4)의 결과 (1)과 같이 괄호가 생성되었습니다. 또한 예시 4)의 결과 (2)와 같이 데이터 타입이 tuple인 것을 확인할 수 있습니다.

예시 4)

tuple_4 = ('C',)
tuple_4
type(tuple_4)

결과 (1) ▷ ('C',)
결과 (2) ▷ tuple

○ 튜플과 리스트의 공통점

튜플은 리스트와 같이 순서가 있는 시퀀스 타입입니다. 그렇기 때문에 리스트와 같이 인덱스(Index)를 사용할 수 있습니다. 인덱스를 사용할 수 있으므로 슬라이싱 역시 사용할 수 있습니다. 또한 튜플도 리스트와 같은 이터레이터 오브젝트이기 때문에 for문을 사용할 수 있습니다. 


○ 튜플과 리스트의 차이점

(1) 데이터의 변경 가능 여부

리스트는 한 번 정의된 데이터의 변경이 가능하지만, 튜플은 한 번 정의된 데이터의 값을 변경할 수 없습니다. 예시 5)와 같이 리스트는 첫 번째 데이터를 'one'으로 바꾸는 데 성공하는 반면, 예시 6)과 같이 튜플은 item assignment를 제공하지 않는다는 TypeError가 발생한 것을 볼 수 있습니다.  

예시 5)

list_1 = [1, 2, 3]
list_1[0] = 'one'
list_1

결과 ▷ ['one', 2, 3]
예시 6)

tuple_5 = 1, 2, 3
tuple_5[0] = 'one'
tuple_5

결과 ▷ 	TypeError                                 
		Traceback (most recent call last)
		<ipython-input-13-947f61f9a7c4> in <module>
		      1 tuple_5 = 1, 2, 3
		----> 2 tuple[0] = 'one'
		      3 tuple_5

		TypeError: 'type' object does not support item assignment

(2) 데이터의 추가 및 삭제 가능 여부

리스트는 새로운 데이터를 추가하거나 기존의 데이터를 삭제할 수 있는 반면에 튜플은 한 번 정의된 데이터의 수를 변경할 수 없습니다. 그렇기 정의된 튜플에 새로운 데이터를 추가하거나 삭제할 수 없습니다. 예시 7)과 같이 새로운 데이터 4를 추가로 입력하려고 할 때 append Attribute를 가지고 있다고 하는 AttirbuteError가 발생한 것을 볼 수 있습니다. 튜플은 데이터의 추가 및 삭제를 할 수 없기 때문에 리스트가 가지고 있는 append, remove와 같은 메소드를 가지고 있지 않습니다. 

예시 7)

tuple_6 = 1, 2, 3
tuple_6.append(4)
tuple_6

결과 ▷ 	AttributeError
		Traceback (most recent call last)
		<ipython-input-15-d6eaae4232be> in <module>
		      1 tuple_6 = 1, 2, 3
		----> 2 tuple_6.append(4)
		      3 tuple_6

		AttributeError: 'tuple' object has no attribute 'append'

(3) 메소드의 범위

튜플이 가진 메소드는 help 메소드를 통해 확인할 수 있습니다(예시 8) 참조). 아랫 부분에 보면 튜플은 count, index 메소드만 가진 것을 확인할 수 있습니다. 튜플에서의 count메소드와 index메소드의 사용 방법은 리스트에서 사용 방법과 동일합니다. 

예시 8)

help(tuple)

결과 ▷
Help on class tuple in module builtins:

class tuple(object)
 |  tuple(iterable=(), /)
 |  
 |  Built-in immutable sequence.
 |  
 |  If no argument is given, the constructor returns an empty tuple.
 |  If iterable is specified the tuple is initialized from iterable's items.
 |  
 |  If the argument is a tuple, the return value is the same object.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __ge__(self, value, /)
 |      Return self>=value.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __getitem__(self, key, /)
 |      Return self[key].
 |  
 |  __getnewargs__(self, /)
 |  
 |  __gt__(self, value, /)
 |      Return self>value.
 |  
 |  __hash__(self, /)
 |      Return hash(self).
 |  
 |  __iter__(self, /)
 |      Implement iter(self).
 |  
 |  __le__(self, value, /)
 |      Return self<=value.
 |  
 |  __len__(self, /)
 |      Return len(self).
 |  
 |  __lt__(self, value, /)
 |      Return self<value.
 |  
 |  __mul__(self, value, /)
 |      Return self*value.
 |  
 |  __ne__(self, value, /)
 |      Return self!=value.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  __rmul__(self, value, /)
 |      Return value*self.
 |  
 |  count(self, value, /)
 |      Return number of occurrences of value.
 |  
 |  index(self, value, start=0, stop=9223372036854775807, /)
 |      Return first index of value.
 |      
 |      Raises ValueError if the value is not present.
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.

(3.1) count메소드 사용 방법

예시 9)와 같이 tuple에 각 숫자에 해당하는 데이터 갯수가 각 숫자와 동일하게 입력한 뒤에 4라는 데이터의 갯수를 파악해보도록 하겠습니다. 그러면 4라는 데이터의 갯수가 4개인 것을 확인할 수 있습니다. 

예시 9)

tuple_7 = 1, 2, 2, 3, 3, 3, 4, 4, 4, 4
tuple_7.count(4)

결과 ▷ 4

(3.2) Index메소드 사용 방법 

index를 메소드를 통하여 예시 10)과 같이 데이터 4의 index를 확인해보도록 하겠습니다. 그러면 데이터 4의 인덱스 값이 3이라는 것을 알 수 있습니다.

예시 10)

tuple_8 = 1, 2, 3, 4, 5
tuple_8.index(4)

결과 ▷ 3

(4) 메모리 크기

튜플은 리스트보더 더 적은 메모리 공간을 사용합니다. 예시 11)과 같이 같은 데이터를 리스트와 튜플에 정의하고 두 개의 메모리 크기를 비교해보겠습니다. 그러면 예시 11)의 결과 (1)과 같이 리스트의 메모리 크기는 96인 반면에, 예시 11)의 결과(2)와 같이 튜플의 메모리 크기는 80으로 튜플이 리스트보다 더 적은 메모리 공간을 사용한 것을 확인할 수 있습니다. 이처럼 데이터의 갯수가 4개임에도 불구하고 16정도의 차이가 발생하는데, 데이터의 갯수가 더욱 많아질 경우 메모리를 차지하는 차이가 굉장히 커질 수 있다는 것을 예측할 수 있습니다. 

예시 11)

list_3 = ['C', 'O', 'D', 'A']
tuple_9 = 'C', 'O', 'D', 'A'

import sys
sys.getsizeof(list_3)
sys.getsizeof(tuple_9)

결과 (1) ▷ 96 
결과 (2) ▷ 80

(5) 생성 속도

튜플은 리스트보다 더욱 빨리 생성됩니다. 그 이유는 튜플은 메모리 상에 하나의 블록으로 저장되지만, 리스트는 두 개의 블록에 각각 오브젝트에 대한 정보와 데이터가 저장되기 때문에 튜플보다는 생성되는 속도가 느립니다. 예시 12)와 같이 튜플과 리스트의 생성 속도를 비교해보도록 하겠습니다. 예시 12-1)과 예시 12-2)의 결과를 비교해보면 튜플이 약 3배 이상 빨리 생성되는 것을 확인할 수 있습니다. 

예시 12-1)

%timeit list_4 = ['C', 'O', 'D', 'A']

결과 ▷ 76.9 ns ± 6.8 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

----------------------------------------------------------------------------------

예시 12-2)

%timeit tuple_10 = 'C', 'O', 'D', 'A'

결과 ▷ 22.2 ns ± 3.92 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

(6) 인덱싱 속도

튜플은 리스트에 비해서 인덱스를 사용하여 데이터에 접근하는 속도가 더 빠릅니다. 예시 13)과 같이 튜플과 리스트의 인덱싱 속도를 비교해보겠습니다. 예시 13-1)과 예시 13-2)의 결과를 보면 알 수 있듯이 큰 차이는 아니지만 튜플이 리스트의 인덱싱 속도보다 조금 더 빠른 것을 볼 수 있습니다. 

예시 13-1)

list_5 = ['C', 'O', 'D', 'A']
%timeit list_5[0]

결과 ▷ 56.3 ns ± 3.73 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

------------------------------------------------------------------------------------

예시 13-2)

tuple_11 = 'C', 'O', 'D', 'A'
%timeit tuple_11[0]

결과 ▷ 55.2 ns ± 8.65 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

○ 튜플의 장점 및 단점

튜플의 장점 및 단점을 요약한 내용은 [표 - 1]과 같습니다. 튜플은 리스트에 비해 적은 메모리를 사용하고, 생성 시간이 빠릅니다. 또한 인덱스를 사용하여 튜플의 데이터에 접근하는 시간이 비교적 짧습니다. 반대로 튜플은 데이트의 값을 변경하거나 추가 및 삭제를 할 수 없으며, 데이터의 구조를 sorted함수를 사용하여 정렬할 수 없습니다. 튜플은 오브젝트를 정의한 뒤 데이터의 값을 변경, 추가, 삭제, 정렬을 해야할 필요가 있을 경우에는 리스트를 사용하며, 한 번 정의된 데이터가 변경되면 안 될 경우 또는 더 좋은 퍼포먼스(메모리가 적은)를 위해서는 튜플을 사용합니다. 

[표 - 1] 튜플의 장점 및 단점
장점 단점

1. 적은 메모리를 사용한다.

1. 데이터 값을 변경할 수 없다.

2. 생성 시간이 빠르다.

2. 데이터를 추가하거나 제거할 수 없다.

3. 인덱스를 사용하여 데이터에 접근하는 시간이 짧다.

3. Sorted 함수를 사용하여 아이템을 순서대로 정렬할 수 없다.