Кортежи 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