Python Tuple проти List: Подібності та відмінності, пояснення

У цій інструкції ми розглянемо ключові подібності та відмінності між кортежами та списками в мові Python. Також ви з’ясуєте, в яких ситуаціях краще використовувати саме кортеж.

Списки та кортежі є вбудованими типами даних у Python, які використовуються для зберігання набору елементів.

Від індексації та слайсингу до можливості зберігати різні типи даних, кортежі та списки на перший погляд можуть здаватися дуже схожими. Тому розуміння їх відмінностей та подібностей допоможе вам ефективніше вибирати, яку структуру даних використовувати у вашому коді.

Давайте почнемо.

👩🏽‍💻 Ви можете використовувати Python REPL або онлайн-редактор Python від techukraine.net для практичного застосування коду під час вивчення матеріалу.

Порівняння кортежів і списків в Python: спільні риси

Спочатку розглянемо, що спільного між списками та кортежами. Для зручності, ми наведемо приклади для обох структур даних.

#1. Ітерація в Python

В Python списки зазвичай створюються за допомогою квадратних дужок, а кортежі – круглих. Кортеж також можна створити як послідовність значень, розділених комами, без використання дужок.

Обидві структури є ітерованими, тобто їх можна обходити за допомогою циклу for.

В наведеному нижче прикладі показано, як використовувати цикл для перебору списку.

nums = [2,6,7,10]
print(f"Тип nums: {type(nums)}")
for num in nums:
  print(num)

# Вивід
Тип nums: <class 'list'>
2
6
7
10

Аналогічно, можна використовувати цикл для перебору кортежу, як показано нижче.

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 = "Coding!"

Наступний фрагмент коду показує, як list(рядок) повертає список, де кожен елемент – це символ з рядка.

list_from_str = list(sample_str)
print(list_from_str)

# Вивід
['C', 'o', 'd', 'i', 'n', 'g', '!']

Подібно, кортеж можна створити з рядка або іншої послідовності за допомогою tuple(послідовність). Наступний код демонструє цей процес.

tuple_from_str = tuple(sample_str)
print(tuple_from_str)

# Вивід
('C', 'o', 'd', 'i', 'n', 'g', '!')

#3. Підтримка індексації та слайсингу

В Python індексація починається з нуля, тобто перший елемент має індекс 0, другий – 1 і так далі. Також підтримується від’ємна індексація, де останній елемент має індекс -1, передостанній -2 і так далі.

list_from_str = ['C', 'o', 'd', 'i', 'n', 'g', '!']
print(list_from_str[1])
# o

Елемент з індексом -2 – це передостанній елемент, ‘g’.

tuple_from_str = ('C', 'o', 'd', 'i', 'n', 'g', '!')
print(tuple_from_str[-2])
# g

Слайсинг дозволяє працювати з певними частинами списку або кортежу. Синтаксис список[start:end] повертає фрагмент списку, починаючи з індексу start і закінчуючи end - 1. Значення за замовчуванням для start – 0, а для end – останній елемент.

Кортежі можна слайсувати, використовуючи той самий синтаксис. Давайте створимо слайси зі списку та кортежу, які ми створили раніше.

list_from_str = ['C', 'o', 'd', 'i', 'n', 'g', '!']
print(list_from_str[0:5])

['C', 'o', 'd', 'i', 'n']

Окрім значень початку та кінця, ви можете вказати крок. Синтаксис tuple[start:end:step] повертає фрагмент кортежу від start до end - 1 з заданим кроком.

tuple_from_str = ('C', 'o', 'd', 'i', 'n', 'g', '!')
print(tuple_from_str[::2])

('C', 'd', 'n', '!')

Тут ми встановили крок рівний 2, тому зріз містить кожен другий елемент.

#4. Зберігання різних типів даних

В прикладах вище всі елементи списків і кортежів мали один і той же тип даних.

Однак можна зберігати значення різних типів даних в одному списку або кортежі.

У наступному фрагменті коду student_list містить ім’я студента як рядок, вік як ціле число та оцінки у вигляді числа з плаваючою комою.

student_list = ["John",22,96.5]
for item in student_list:
  print(f"{item} має тип {type(item)}")

# Вивід
John має тип <class 'str'>
22 має тип <class 'int'>
96.5 має тип <class 'float'>

Аналогічно, ми можемо зробити приклад з кортежем.

student_tuple = ("Jane",23,99.5)
for item in student_tuple:
  print(f"{item} має тип {type(item)}")

# Вивід
Jane має тип <class 'str'>
23 має тип <class 'int'>
99.5 має тип <class 'float'>

#5. Перевірка наявності елемента

І списки, і кортежі дозволяють перевірити, чи присутній певний елемент у структурі даних. Оператор in використовується для перевірки, чи присутній елемент у списку або кортежі.

Вираз елемент in iterable повертає True, якщо iterable містить елемент, інакше повертає False.

"Alex" in student_list
# False

"Jane" in student_tuple
# True

На цьому етапі ви ознайомилися зі спільними рисами списків та кортежів в Python. Далі ми розглянемо їх ключові відмінності.

Порівняння кортежів та списків в Python: основні відмінності

#1. Змінюваність списків та незмінюваність кортежів

Найбільш значна відмінність між списками та кортежами в Python полягає в тому, що кортеж є незмінним, тобто його не можна модифікувати після створення.

▶️ Ось приклад.

tuple1 = ("Java","Python","C++")
tuple1[0] = "Rust"

# Вивід
----> 2 tuple1[0] = "Rust"

TypeError: 'tuple' object does not support item assignment

Список, на відміну від кортежу, є змінною структурою даних, тобто елементи списку можна змінювати, наприклад, змінювати значення за певним індексом.

list1 = ["Java","Python","C++"]
list1[0] = "Rust"
print(list1)

# Вивід
['Rust', 'Python', 'C++']

#2. Динамічна довжина списків та фіксована довжина кортежів

Список Python – це структура даних зі змінною довжиною.

Ви можете:

  • Додати елемент в кінець списку.
  • Додати елементи з іншого списку в кінець поточного списку.
  • Видалити елементи зі списку за певним індексом.
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 елементів займають більше пам’яті, ніж кортежі з такою ж кількістю елементів.

Ось наочна ілюстрація:

Метод getsizeof() з вбудованого модуля sys можна використовувати для отримання розміру об’єкта в пам’яті.

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

Коли слід використовувати кортеж Python?

З вищеописаних відмінностей і подібностей між списками та кортежами Python, ми знаємо, що якщо потрібна змінна колекція, слід використовувати список.

А коли натомість краще використовувати кортеж?

Розглянемо це в цьому розділі.

#1. Колекція тільки для читання

Коли потрібна незмінна колекція, необхідно визначати її як кортеж. Наприклад, колір = (243,55,103) – кортеж, що містить RGB значення певного кольору. Визначення кольору як кортежу гарантує, що його значення не можна буде випадково змінити.

Отже, якщо потрібна колекція, яка буде лише для читання і значення не повинні змінюватися протягом виконання програми, варто розглянути можливість використання кортежу. Це допоможе уникнути випадкової зміни значень.

#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' object does not support item assignment

#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. Значення, що повертаються функціями

В Python кортежі часто зустрічаються в якості значень, що повертаються функціями. Якщо функція повертає кілька значень, Python неявно повертає їх як кортеж.

Розглянемо таку функцію 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

Висновок

Сподіваємось, цей посібник надав вичерпне порівняння кортежів та списків в Python.

Підведемо підсумки:

  • Списки та кортежі є вбудованими структурами даних в Python.
  • Спільні риси: ітерованість, підтримка індексації, слайсинг, можливість зберігати різні типи даних та оператор in для перевірки наявності елемента.
  • Ключова відмінність: списки є змінними, а кортежі – незмінними.
  • Інші відмінності: фіксована довжина кортежів та динамічна довжина списків, кортежі займають менше пам’яті.
  • Коли слід використовувати кортежі? Для незмінних колекцій, ключів словника та аргументів функцій.

Далі перегляньте проєкти Python, щоб попрактикуватись. Або дізнайтесь про методи видалення повторюваних елементів зі списків Python. Вдалих навчань! Та щасливого кодування! 👩🏽‍💻