list와 tuple은 얼핏보면 상당히 비슷하다.
하지만 몇몇 상황에서 list를 선택하는지 tuple을 선택하는지에 따라 다른 결과를 볼 수도 있다.
list와 tuple의 공통점과 차이점을 간단히 알아보자.
Tuple은 일반적으로 2개에서 5개 사이의 요소들을 저장할때 사용되며,
특정 데이터를 ad hoc(즉석적으로) 하게 표현하고 싶을때 사용된다.
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
my_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
my_list[0] # 1
my_tuple[0] # 1
for item in my_list:
pass
for item in my_tuple:
pass
my_list[0] = "Hello" # various_list = ["Hello", 2, 3, 4, 5, 6, 7, 8, 9, 10]
my_tuple[0] = "Hello" # TypeError: 'tuple' object does not support item assignment
my_dict = {my_list: "My List!"} # TypeError: unhashable type: 'list'
my_dict = {my_tuple: "My tuple!"} # 정상 작동
딕셔너리의 키값은 불변한(immutable) 값만 올 수 있기 때문이다.
하지만, 만약 다음과 같이 튜플에 리스트가 들어있는 경우라면 이 경우는 키 값으로 사용할 수 없다.
various_tuple = ("GoodBye", [2016, 2017, 2018])
my_dict = {various_tuple: "My tuple!"} # TypeError: unhashable type: 'list'
참고로,
다음과 같이 문자열 또한 불변한 객체이기 때문에 딕셔너리의 키 값으로 사용할 수 있는 것이다.
my_string = "Hello"
my_string[0] = "B" # TypeError: 'str' object does not support item assignment
list의 경우, 다음과 같은 방식들로 객체를 복사할 경우 서로 Identity가 다른 객체로 복사된다.
즉, is 로 비교를 했을때 같은 객체가 아닌 새로운 객체가 생긴다는 뜻이다.
>>> l1 = [1, 2, 3]
>>> l2 = l1[:]
>>> l1 is l2
False
>>> l1 = [1, 2, 3]
>>> l2 = list(l1)
>>> l1 is l2
False
하지만 tuple의 경우, 동일한 방식으로 복사할 경우 서로 Identity가 같은 객체로 복사된다.
즉, list처럼 새로운 메모리에 값을 할당하는 것이 아니라,
복사된 변수가 원본과 같은 객체를 가리키고있다는 뜻이다.
>>> t1 = (1, 2, 3)
>>> t2 = t1[:]
>>> t1 is t2
True
>>> t1 = (1, 2, 3)
>>> t2 = tuple(t1)
>>> t1 is t2
True
이는 파이썬에서 메모리를 절약하고 성능을 높이기 위한 일종의 전략이다.
어차피 tuple은 불변객체이므로 값을 바꿀 수 없다.
따라서 원본이나 사본의 값을 바꾸었을때, 반대편의 값도 함께 바뀌는 것에 대한 걱정을 할 필요가 없다.
그래서 객체를 굳이 복사하지 않고 기존의 객체에 변수만 할당하는 식으로 효율을 높이는 것이다.