Кортежи tuple в Python: свойства и отличие от списков

Обновлено:

С классом:

tuple

мы уже знакомы.

Мы умеем:

  • создавать кортежи;
  • получать элементы по индексам;
  • использовать срезы;
  • обходить кортежи в цикле for;
  • распаковывать их в несколько переменных.

Теперь соберём основные свойства tuple вместе и посмотрим, когда кортеж удобнее списка.


1. Основные свойства tuple

Кортеж является:

  • итерируемым объектом;
  • упорядоченной последовательностью;
  • неизменяемым объектом.

Например:

coordinates = (
    10,
    25,
    40,
)

Элементы сохраняют свой порядок:

index 0 → 10
index 1 → 25
index 2 → 40

2. tuple можно обходить

Так как кортеж является итерируемым объектом:

technologies = (
    'Python',
    'SQL',
    'Django',
)

for technology in technologies:
    print(technology)

Результат:

Python
SQL
Django

3. Работают индексы

numbers = (
    10,
    20,
    30,
)

print(numbers[0])
print(numbers[-1])

Результат:

10
30

4. Работают срезы

numbers = (
    10,
    20,
    30,
    40,
    50,
)

print(
    numbers[1:4]
)

Результат:

(20, 30, 40)

Срез кортежа возвращает:

tuple

Неизменяемость

5. Элемент нельзя заменить

Со списком мы можем написать:

numbers = [
    10,
    20,
    30,
]

numbers[1] = 200

Но с кортежем:

numbers = (
    10,
    20,
    30,
)

numbers[1] = 200

возникнет:

TypeError

Кортеж не поддерживает изменение элементов.


6. Нельзя удалить отдельный элемент

Например:

numbers = (
    10,
    20,
    30,
)

del numbers[1]

также приведёт к:

TypeError

Нельзя изменить длину существующего кортежа или заменить находящиеся в нём ссылки.


Важный нюанс

7. Неизменяем кортеж, а не обязательно объекты внутри него

Например:

data = (
    'Python',
    [10, 20],
)

Мы не можем написать:

data[1] = [30, 40]

Но второй элемент является списком, а список изменяем:

data[1].append(30)

print(data)

Результат:

('Python', [10, 20, 30])

Сам tuple остался тем же:

index 0 → ссылка на строку
index 1 → ссылка на тот же список

Но объект списка, на который он ссылается, изменился.

Поэтому:

Неизменяемость tuple означает, что нельзя заменить, добавить или удалить его элементы. Она не делает автоматически неизменяемыми все вложенные объекты.


Методы tuple

У кортежа очень мало собственных методов.

Основные:

count()
index()

count()

8. Количество совпадений

Метод:

count()

работает так же, как у списка.

numbers = (
    10,
    20,
    10,
    30,
    10,
)

print(
    numbers.count(10)
)

Результат:

3

Если значения нет:

print(
    numbers.count(100)
)

Результат:

0

index()

9. Индекс первого совпадения

numbers = (
    10,
    20,
    30,
    20,
)

print(
    numbers.index(20)
)

Результат:

1

Возвращается индекс первого найденного элемента.


10. start и stop

Как и у списка, можно ограничить область поиска:

numbers = (
    10,
    20,
    30,
    20,
    40,
)

print(
    numbers.index(
        20,
        2,
    )
)

Результат:

3

11. Если элемента нет

numbers = (
    10,
    20,
    30,
)

numbers.index(100)

возникнет:

ValueError

Почему у tuple так мало методов

Список является изменяемым, поэтому у него существуют методы:

append()
extend()
insert()

pop()
remove()
clear()

reverse()
sort()

У tuple таких методов нет, потому что они должны были бы изменять существующий объект.

Кортеж неизменяем.

Поэтому из знакомых нам собственных методов у него фактически остаются операции получения информации:

count()
index()

list и tuple

12. Основное различие

Список:

numbers = [
    10,
    20,
    30,
]

можно изменять.

Кортеж:

numbers = (
    10,
    20,
    30,
)

после создания изменить нельзя.


13. Сравнение

Свойство list tuple
Упорядоченный Да Да
Итерируемый Да Да
Индексы Да Да
Срезы Да Да
Можно изменить элементы Да Нет
Можно менять длину Да Нет
count() Да Да
index() Да Да
Методы добавления и удаления Да Нет

Память

14. Кортеж обычно занимает меньше памяти

В CPython кортеж обычно требует меньше памяти, чем список с тем же количеством элементов.

Например:

from sys import getsizeof


numbers_list = [
    10,
    20,
    30,
    40,
    50,
]

numbers_tuple = (
    10,
    20,
    30,
    40,
    50,
)

print(
    getsizeof(numbers_list)
)

print(
    getsizeof(numbers_tuple)
)

Конкретные размеры зависят от версии и реализации Python.

Но обычно:

tuple → меньше памяти
list  → больше памяти

Одна из причин заключается в том, что список должен поддерживать изменение длины и поэтому является динамическим массивом с дополнительной вместимостью.

Кортеж после создания менять размер не умеет, поэтому такая дополнительная возможность ему не нужна.


Производительность

15. tuple иногда немного быстрее

В CPython некоторые операции с кортежами могут быть немного быстрее, чем с аналогичными списками.

Например:

  • создание;
  • обход;
  • некоторые операции чтения.

Но разница обычно небольшая.

Поэтому не стоит выбирать tuple исключительно ради нескольких процентов производительности.

Главное различие заключается в смысле данных:

данные должны изменяться → list

набор значений фиксированный → tuple

Когда использовать tuple

16. Фиксированная группа значений

Например, координаты точки:

coordinates = (
    41.7151,
    44.8271,
)

Количество и смысл значений фиксированы:

latitude
longitude

Нам обычно не нужно внезапно добавлять третью или четвёртую координату в этот объект.

Кортеж хорошо показывает это намерение.


17. Размеры объекта

screen_size = (
    1920,
    1080,
)

Здесь два значения представляют одну логическую сущность:

width
height

Это фиксированная структура из двух значений.


18. Цвет

Например:

rgb = (
    255,
    120,
    40,
)

Здесь ожидаются три компонента:

red
green
blue

Такой набор логически фиксирован.


Возврат нескольких значений из функции

19. Кортеж удобно использовать для нескольких результатов

Например:

def get_min_max(numbers):
    return (
        min(numbers),
        max(numbers),
    )

Используем:

result = get_min_max(
    [10, 50, 20, 5]
)

print(result)

Результат:

(5, 50)

Можно сразу распаковать:

minimum, maximum = (
    get_min_max(
        [10, 50, 20, 5]
    )
)

print(minimum)
print(maximum)

Результат:

5
50

На практике Python позволяет записать return и без явных круглых скобок:

def get_min_max(numbers):
    return min(numbers), max(numbers)

Результатом всё равно будет кортеж.


Фиксированные данные в списке

20. Список кортежей

Мы уже использовали конструкции вроде:

employees = [
    (
        'Alex',
        'Brown',
        'Developer',
    ),
    (
        'Emma',
        'Wilson',
        'Designer',
    ),
]

Внешний объект:

list

подходит, потому что количество сотрудников может изменяться:

сотрудника можно добавить
сотрудника можно удалить

Но данные одного сотрудника представлены кортежем:

(
    first_name,
    last_name,
    position,
)

потому что сама структура одной записи фиксирована.

Это хороший пример совместного использования:

list  → изменяемая коллекция записей
tuple → фиксированная структура одной записи

Один элемент в tuple

21. Важна запятая

Кортеж из одного элемента создаётся так:

number = (
    10,
)

print(
    type(number)
)

Результат:

<class 'tuple'>

А:

number = (
    10
)

не создаёт кортеж.

Это просто число в круглых скобках:

print(
    type(number)
)

Результат:

<class 'int'>

Кортеж создаёт именно:

запятая

а не сами круглые скобки.

Поэтому можно даже написать:

number = 10,

и это тоже будет:

tuple

Но запись:

number = (
    10,
)

обычно нагляднее.


Когда выбирать list, а когда tuple

Можно использовать простое правило.

Если коллекция должна изменяться:

shopping_cart = [
    'Laptop',
    'Mouse',
]

логично использовать:

list

Потому что элементы будут:

  • добавляться;
  • удаляться;
  • заменяться.

Если набор значений представляет фиксированную структуру:

resolution = (
    1920,
    1080,
)

удобно использовать:

tuple

Тем самым сам тип объекта сообщает другому разработчику:

Эти значения рассматриваются как фиксированная группа, и менять структуру объекта не предполагается.


Главное по теме

tuple — это:

упорядоченная
итерируемая
неизменяемая
последовательность

Он поддерживает:

len()

indexing
slicing

for
in
not in

и имеет два основных собственных метода:

count()
index()

Главное отличие от списка:

list  → изменяемый
tuple → неизменяемый

В CPython кортеж обычно:

  • занимает немного меньше памяти;
  • в некоторых операциях может быть немного быстрее;
  • имеет значительно меньше методов.

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

Примеры:

coordinates = (
    41.7151,
    44.8271,
)

resolution = (
    1920,
    1080,
)

rgb = (
    255,
    120,
    40,
)

Если же коллекцию предполагается активно изменять, добавляя и удаляя элементы, обычно лучше использовать:

list