튜플은 항목을 _순서_대로 담는 불변 컬렉션이에요.
대부분의 컬렉션(내장 타입인 list, dict, set를 참고해요)과 마찬가지로, tuples에는 여러 데이터 타입을 담을 수 있어요. 다른 tuples도 포함해서요.
튜플의 원소는 for item in <tuple> 구문으로 반복할 수 있어요.
원소의 인덱스와 값이 모두 필요하면 for index, item in enumerate(<tuple>)를 사용할 수 있어요.
다른 시퀀스와 마찬가지로, tuples 안의 원소는 왼쪽에서부터는 0-based index, 오른쪽에서부터는 -1-based index 번호를 사용하는 _대괄호 표기법_으로 접근할 수 있어요.
튜플은 _슬라이스 표기법_이나 <tuple>.copy()로 전체 또는 일부를 복사할 수 있고, 모든 일반 시퀀스 연산을 지원해요.
_불변_이기 때문에 tuples는 가변 시퀀스 연산을 지원하지 않아요.
튜플은 다른 컬렉션 타입에 비해 메모리 공간을 아주 적게 차지하고, 인덱스로 접근할 때 상수 시간(O(1))이 걸려요.
하지만 한번 만들어지면 크기를 바꾸거나 정렬하거나 수정할 수 없어서, 데이터를 자주 변경하거나 갱신해야 할 때는 유연성이 떨어져요.
잦은 갱신이나 확장이 필요하다면 list, collections.deque, array.array가 더 나은 자료 구조일 수 있어요.
튜플은 여러 방법으로 만들 수 있어요. tuple 클래스 생성자를 쓰거나 (<element_1>, <element_2>) (tuple 리터럴) 선언을 사용해요.
tuple() 생성자를 비워 두거나 _이터러블_과 함께 사용하기:>>> no_elements = tuple()
()
# The constructor *requires* an iterable, so single elements must be passed in a list or another tuple.
>>> one_element = tuple([16])
(16,)
문자열은 이터러블이기 때문에, tuple() 생성자에 str 하나를 인자로 넘기면 의외의 결과가 나올 수 있어요:
# String elements (characters) are iterated through and added to the tuple
>>> multiple_elements_string = tuple("Timbuktu")
('T', 'i', 'm', 'b', 'u', 'k', 't', 'u')
다른 이터러블도 원소가 하나씩 추가돼요:
>>> multiple_elements_list = tuple(["Parrot", "Bird", 334782])
("Parrot", "Bird", 334782)
>>> multiple_elements_set = tuple({2, 3, 5, 7, 11})
(2,3,5,7,11)
dict를 반복하면 기본적으로 키를 순회해요.
딕셔너리로 만든 튜플에 키와 값은 모두 담고 싶다면 <dict>.items()를 사용해요.
그러면 (key, value) tuples의 이터레이터가 반환돼요.
>>> source_data = {"fish": "gold", "monkey": "brown"}
>>> multiple_elements_dict_1 = tuple(source_data)
('fish', 'monkey')
>>> multiple_elements_dict_2 = tuple(source_data.items())
(('fish', 'gold'), ('monkey', 'brown'))
tuple() 생성자는 이터러블(또는 아무것도)만 인자로 받기 때문에, 리터럴 방식으로 원소가 하나인 튜플을 만드는 것이 훨씬 쉬워요.
>>> no_elements = ()
()
>>> one_element = ("Guava",)
("Guava",)
일반적으로 tuple 리터럴을 만들 때 괄호는 필요하지 않고, 쉼표만 있으면 돼요.
하지만 대부분의 상황에서는 (<element_1>, <element_2>) 형태가 더 읽기 좋다고 여겨져요.
빈 튜플이나 원소가 하나인 튜플처럼 모호한 경우, 또는 함수가 튜플을 인자로 받는 경우에는 괄호가 필요해요.
>>> elements_separated_with_commas = "Parrot", "Bird", 334782
("Parrot", "Bird", 334782)
>>> elements_with_commas_and_parentheses = ("Triangle", 60, 60, 60)
("Triangle", 60, 60, 60)
다른 tuples를 포함해, 다른 자료 구조도 tuple의 원소로 넣을 수 있어요.
>>> nested_data_structures = ({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird"))
({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird"))
>>> nested_data_structures_1 = (["fish", "gold", "monkey", "brown", "parrot", "grey"], ("fish", "mammal", "bird"))
(["fish", "gold", "monkey", "brown", "parrot", "grey"], ("fish", "mammal", "bird"))
튜플은 더하기 + 연산자로 이어 붙일 수 있어요. 이때 각 tuple이 풀리고, 합쳐진 새로운 tuple이 만들어져요.
>>> new_via_concatenate = ("George", 5) + ("cat", "Tabby")
("George", 5, "cat", "Tabby")
#likewise, using the multiplication operator * is the equivalent of using + n times
>>> first_group = ("cat", "dog", "elephant")
>>> multiplied_group = first_group * 3
('cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant')
튜플 안의 원소는 (다른 시퀀스 타입인 str, list처럼) 대괄호 표기법_으로 접근할 수 있어요.
인덱스는 left --> right (0부터 시작) 또는 right --> left (-1부터 시작_) 방향으로 셀 수 있어요.
튜플은 _슬라이스 표기법_이나 <tuple>.copy()를 사용해 전체 또는 일부를 복사할 수도 있어요.
>>> student_info = ("Alyssa", "grade 3", "female", 8)
#name is at index 0 or index -4
>>> student_name = student_info[0]
Alyssa
>>> student_name = student_info[-4]
Alyssa
#age is at index 3 or index -1
>>> student_age_1 = student_info[3]
8
>>> student_age_2 = student_info[-1]
8
튜플 안의 원소는 for item in <tuple> 구문으로 루프를 돌며 _반복_할 수 있어요.
인덱스와 값이 모두 필요하면 for index, item in enumerate(<tuple>)를 사용할 수 있어요.
>>> student_info = ("Alyssa", "grade 3", "female", 8)
>>> for item in student_info:
... print(item)
...
Alyssa
grade 3
female
8
>>> for index, item in enumerate(student_info):
... print("Index is: " + str(index) + ", value is: " + str(item) + ".")
...
Index is: 0, value is: Alyssa.
Index is: 1, value is: grade 3.
Index is: 2, value is: female.
Index is: 3, value is: 8.
튜플은 조직상 또는 개념상 동질적인 데이터를 담아 하나의 정보 단위로 다루는 _레코드_로 자주 사용돼요. 개별 원소의 데이터 타입이 서로 다르더라도 말이에요.
>>> student_info = ("Alyssa", "grade 3", "female", 8)
튜플은 동질적이고 불변인 데이터 시퀀스가 필요할 때도 사용해요. 예를 들어 hashability를 만족해야 하거나, set에 저장하거나, 딕셔너리의 키를 만들 때처럼요.
tuples는 대부분의 경우 _불변_이지만, 어떤 자료 구조나 객체든 담을 수 있기 때문에 원소 중 하나라도 _가변 타입_이면 _가변_이 될 수 있다는 점에 주의해요.
tuple 안에 가변 데이터 타입을 넣으면 그 tuple은 해시할 수 없게 돼요.
>>> cmyk_color_map = {
(.69, .3, .48, .1) : ("Teal 700", (59, 178, 146), 0x3BB292),
(0, .5, 1, 0) : ("Pantone 151", (247, 127, 1), 0xF77F01),
(.37, .89, 0, .44) : ("Pantone 267", (89, 16, 142), 0x59108E),
(0, 1, .46, .45) : ("Pantone 228", (140, 0, 76), 0x8C004C)
}
>>> unique_rgb_colors = {
(59, 178, 146),
(247, 127, 1),
(89, 16, 142),
(140, 0, 76),
(76, 0, 140)
}
>>> teal_700 = hash((59, 178, 146))
>>> teal_700 = hash(("Pantone 228", [(140, 0, 76), 0x8C004C]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
튜플은 _레코드_로 자주 사용되지만, 그 안의 데이터는 위치/_인덱스_로만 접근할 수 있어요.
collections 모듈의 namedtuple() 클래스는 기본 튜플 기능을 확장해 원소를 _이름_으로 접근할 수 있게 해줘요.
또한 dataclass를 활용하면 비슷하게 이름이 붙은 속성 기능을 제공할 수 있어요. 다만 장단점이 있어요.