Кортежи в Python (tuple)
- Примеры кортежей
- Зачем использовать кортеж вместо списка
- Работа с кортежами
- Создание
- Упаковка
- Распаковка
- Обращение к элементу и поиск в кортеже
- Сравнение
- Перебор
- Сортировка
- Удаление
- Методы и особые операции
- Срез
- Длина кортежа
- Конкатенация
- Повторение
- Индекс заданного элемента
- Число вхождений элемента
- Преобразование
- tuple → str
- tuple → list
- tuple → dict
- Именованные кортежи
- Tuple index out of range
Кортеж (tuple) — ещё один вид последовательностей в Python.
По своей природе они очень схожи со списками, но, в отличие от последних, являются неизменяемыми.
# кортеж
immutable_tuple = (4, 5, 6)
immutable_tuple[0] = 404
>
Traceback (most recent call last):
immutable_tuple[0] = 404
TypeError: 'tuple' object does not support item assignment
# список
mutable_list = [7, 8, 9]
mutable_list[0] = 1
print(mutable_list)
> [1, 8, 9]
Как видно, в литеральной форме кортеж python 3 записывается в виде последовательности элементов в круглых скобках, в то время как для списков характерны квадратные.
👉 Некоторые особенности кортежей:
- они упорядочены по позициям;
- tuple могут хранить и содержать внутри себя объекты любых типов (и даже составных);
- доступ к элементам происходит по смещению, а не по ключу;
- в рамках этой структуры данных определены все операции, основанные на применении смещения (индексирование, срез);
- кортежи поддерживают неограниченное количество уровней вложенности;
- кортежи хранят указатели на другие объекты, а значит их можно представлять, как массивы ссылок;
- они позволяют очень просто менять местами значения двух переменных.
x = 100
y = 200
x, y = y, x
print(x)
> 200
print(y)
> 100
Примеры кортежей
# пустой кортеж
empty_tuple = ()
# кортеж из 4-х элементов разных типов
four_el_tuple = (36.6, 'Normal', None, False)
# пример tuple, что содержит вложенные элементы
nested_elem_tuple = (('one', 'two'), ['three', 'four'], {'five': 'six'}, (('seven', 'eight'), ('nine', 'ten')))
print(nested_elem_tuple)
> (('one', 'two'), ['three', 'four'], {'five': 'six'}, (('seven', 'eight'), ('nine', 'ten')))
Зачем использовать кортеж вместо списка
Тем, кто уже успел познакомиться со списками в Python, может показаться не очевидным смысл использования кортежей. Ведь фактически, списки могут делать всё то же самое и даже больше. Это вполне естественный вопрос, но, разумеется, у создателей языка найдётся на него ответ:
- Неизменяемость — именно это свойство кортежей, порой, может выгодно отличать их от списков.
- Скорость — кортежи быстрее работают. По причине неизменяемости кортежи хранятся в памяти особым образом, поэтому операции с их элементами выполняются заведомо быстрее, чем с компонентами списка.
- Безопасность — неизменяемость также позволяет им быть идеальными кандидатами на роль констант. Константы, заданные кортежами, позволяют сделать код более читаемым и безопасным.
- Использование tuple в других структурах данных — кортежи применимы в отдельных структурах данных, от которых python требует неизменяемых значений. Например ключи словарей (dicts) должны состоять исключительно из данных immutable-типа.
💡 Кроме того, кортежи удобно использовать, когда необходимо вернуть из функции несколько значений:
def get_status(service_name):
return None, f"service {service_name} is OK!"
print(type(get_status('nginx')))
> <class 'tuple'>
error, message = get_status('nginx')
print(error)
print(message)
> None
> service nginx is OK!
Работа с кортежами
Создание
Как и другие коллекции языка Питон, кортеж можно создать двумя способами.
Способ №1: Литеральное объявление:
literal_creation = ('any', 'object')
print(literal_creation)
> ('any', 'object')
print(type(literal_creation))
> <class 'tuple'>
Способ №2: Через функцию tuple()
:
tuple_creation = tuple('any iterable object')
print(tuple_creation)
> ('a', 'n', 'y', ' ', 'i', 't', 'e', 'r', 'a', 'b', 'l', 'e', ' ', 'o', 'b', 'j', 'e', 'c', 't')
print(type(tuple_creation))
> <class 'tuple'>
💁♀️ Важно, чтобы аргумент, передаваемый в tuple()
был итерируемым объектом:
incorrect_creation = tuple(777)
>
Traceback (most recent call last):
incorrect_creation = tuple(777)
TypeError: 'int' object is not iterable
Упаковка
Упаковкой кортежа называют присваивание его какой-то переменной, что, по сути, совпадает с операцией объявления.
Стоит обратить внимание 2 момента:
- Выражения
some_tuple = (11, 12, 13)
иsome_tuple = 11, 12, 13
тождественны. - Для объявления кортежа, включающего один единственный элемент, нужно использовать завершающую запятую:
is_tuple = ('a',)
is_tuple_too = 'b',
not_a_tuple = 'c'
print(type(is_tuple))
print(type(is_tuple_too))
print(type(not_a_tuple))
> <class 'tuple'>
> <class 'tuple'>
> <class 'str'>
Распаковка
Обратная операция, смысл которой в том, чтобы присвоить значения элементов кортежа отдельным переменным.
notes = ('Do', 'Re', 'Mi', 'Fa', 'Sol', 'La', 'Si')
do, re, mi, fa, sol, la, si = notes
print(mi)
> Mi
Количество переменных должно совпадать с числом элементов tuple
Однако, если необходимо получить лишь какие-то отдельные значения, то в качестве "ненужных" переменных позволено использовать символ нижнего подчеркивания "_":
night_sky = 'Moon', 'Stars'
moon, _ = night_sky
print(moon)
> Moon
Обращение к элементу и поиск в кортеже
Обратиться к элементу кортежа можно по номеру его позиции. Причём как с начала, так и с конца:
# Mike - [0], Leo - [1], Don - [2], Raph - [3]
turtles = ('Mike', 'Leo', 'Don', 'Raph')
# Mike - [-4], Leo - [-3], Don - [-2], Raph - [-1]
print(turtles[1])
print(turtles[-2])
print(turtles[2] == turtles[-2])
> Leo
> Don
> True
Если элемент кортежа есть вложенный кортеж, то применяются дополнительные квадратные скобки (в зависимости от уровня вложенности). Например, чтобы обратиться ко второму элементу второго элемента, следует поступить так:
input_box = ('firstbox', (15, 150))
# помним про индексацию, ведущую своё начало с 0
print(input_box[1][1])
> 150
Узнать, присутствует ли объект среди элементов кортежа, можно с помощью оператора in:
song = ('Roses', 'are', 'Red')
print('Red' in song)
print('Violet' in song)
> True
> False
Сравнение
tuple_A = 2 * 2,
tuple_B = 2 * 2 * 2,
tuple_C = 'a',
tuple_D = 'z',
tuple_E = (42, 'maximum')
tuple_F = (42, 'minimum')
tuple_Z = 999,
# при сравнении кортежей, числа сравниваются по значению
print(tuple_A < tuple_B)
> True
# строки в лексикографическом порядке
print(tuple_C < tuple_D)
> True
# при равенстве элементов на одинаковых позициях, сравниваются элементы на следующих
print(tuple_E < tuple_F)
> True
# сравнение элементов продолжается до первого неравенства
print(tuple_Z < tuple_F)
> False
Перебор
Наиболее простым и очевидным способом перебрать элементы кортежа является обход его в цикле for
:
my_tuple = ('Wise', 'men', 'say', 'only', 'fools', 'rush', 'in')
# Вывести все элементы кортежа
for word in my_tuple:
print(word)
>
Wise
men
say
only
fools
rush
in
Сортировка
Нет ничего проще, чем отсортировать готовый кортеж. В этом наш друг и помощник — прекрасная функция sorted()
:
not_sorted_tuple = (10**5, 10**2, 10**1, 10**4, 10**0, 10**3)
print(not_sorted_tuple)
> (100000, 100, 10, 10000, 1, 1000)
sorted_tuple = tuple(sorted(not_sorted_tuple))
print(sorted_tuple)
> (1, 10, 100, 1000, 10000, 100000)
Удаление
Добавить или удалить элемент содержащийся в tuple нельзя, по причине всё той же неизменяемости. Однако сам кортеж стереть с цифрового лица Земли возможно. Оператор del
к нашим услугам:
some_useless_stuff = ('sad', 'bad things', 'trans fats')
del some_useless_stuff
print(some_useless_stuff)
>
Traceback (most recent call last):
print(some_useless_stuff)
NameError: name 'some_useless_stuff' is not defined
Методы и особые операции
Срез
Слайсы кортежей предельно похожи на таковые у строк, а выглядят они следующим образом:
tuple[start:fin:step]
Где start
— начальный элемент среза (включительно), fin
— конечный (не включительно) и step
— "шаг" среза.
float_tuple = (1.1, 0.5, 45.5, 33.33, 9.12, 3.14, 2.73)
print(float_tuple[0:3])
> (1.1, 0.5, 45.5)
# тождественная запись
print(float_tuple[:3])
> (1.1, 0.5, 45.5)
# если не указывать конечное значение, будут выведены все элементы до конца
print(float_tuple[0:])
> (1.1, 0.5, 45.5, 33.33, 9.12, 3.14, 2.73)
# не указывать начальное - с начала
print(float_tuple[:])
> (1.1, 0.5, 45.5, 33.33, 9.12, 3.14, 2.73)
# выведем элементы с шагом 2
print(float_tuple[-7::2])
> (1.1, 45.5, 9.12, 2.73)
# отрицательный шаг позволит вывести tuple в обратном порядке
print(float_tuple[::-1])
> (2.73, 3.14, 9.12, 33.33, 45.5, 0.5, 1.1)
Длина кортежа
Используя функцию len()
, получаем длину/количество элементов:
php = ('p', 'h', 'p')
print(len(php))
> 3
Конкатенация
Для tuple определена операция конкатенации:
storm_1 = ('Lightning',)
union = (' and ',)
storm_2 = ('Thunder',)
print(storm_1 + union + storm_2)
> ('Lightning', ' and ', 'Thunder')
Повторение
Как и в случае с конкатенацией, для кортежей, впрочем, как и для строк, определена операция повторения:
dog_do = ('woof!',)
print(dog_do * 3)
> ('woof!', 'woof!', 'woof!')
Индекс заданного элемента
Метод index()
позволяет получить индекс элемента. Достаточно передать нужное значение элемента, как аргумент метода:
rom = ('I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X')
print(rom.index('X'))
> 9
Число вхождений элемента
Метод count()
ведёт подсчет числа вхождений элемента в кортеж.
AT = ('Finn', 'Jake', 'BiMo', 'Marceline', 'Princess Bubblegum', 'BiMo')
print(AT.count('Finn'))
> 1
print(AT.count('BiMo'))
> 2
Преобразование
tuple → str
Представляем вашему вниманию лёгкий способ преобразовать кортеж в строку при помощи метода join()
:
game_name = ('Breath', ' ', 'of', ' ', 'the', ' ', 'Wild')
game_name = ''.join(game_name)
print(game_name)
> Breath of the Wild
tuple → list
Тут всё ещё проще. Для такой конвертации необходимо всего лишь передать кортеж, как аргумент функции list()
:
dig_tuple = (1111, 2222, 3333)
print(dig_tuple)
> (1111, 2222, 3333)
dig_list = list(dig_tuple)
print(dig_list)
> [1111, 2222, 3333]
tuple → dict
А вот для преобразования кортежа в словарь придётся применить небольшую хитрость, а именно — генератор словарей:
score = (('Eric', 65000), ('Stephany', 87000))
score_dict = dict((x, y) for x, y in score)
print(score_dict)
> {'Eric': 65000, 'Stephany': 87000}
Именованные кортежи
Мощная особенность и настоящая гордость языка.
Именованный кортеж (или named tuple) позволяет программисту обращаться к элементу кортежа не по индексу, а через удобочитаемый заранее заданный идентификатор.
Покажем на примере:
# для начала импортируем сам модуль
from collections import namedtuple
citizen = namedtuple("Citizen", "name age status")
Alex = citizen(name='Alex Mercer', age=27, status='show businessman')
print(Alex.name)
> Alex Mercer
print(Alex.status)
> show businessman
Точечная нотация при обращении к свойству объекта может вызвать невольную ассоциацию с классами. В общем-то одно из применений namedtuple как раз связано с ситуациями, когда нужно передать несколько свойств объекта одним куском.
Tuple index out of range
Такая ошибка может возникнуть, например, при запуске следующего кода:
i_initiate_error = ('west', 'north', 'east', 'south')
print(i_initiate_error[4])
Причина её возникновения в том, что нельзя получить доступ к индексу кортежа за пределами его длины. Эта ошибка может возникать и при совсем нетривиальных обстоятельствах, однако суть её останется прежней. Начинающим программистам стоит помнить, что индексация кортежей начинается с 0, а не с 1.
Кортежи весьма похожи на списки, но очень сложно спорить с тем, что гибкость и функционал последних намного выше. Поэтому, при написании программ, следует, в основном, пользоваться ими, а не кортежами.
Можете пояснить как это работает? Все переменные получаются типа
str
, конечно же конкатенация работает, если добавить запятые в скобки, то получаетсяtuple
, а не строка....Конкатенация
Для tuple определена операция конкатенации:
storm_1 = ('Lightning') Union = (' and ') storm_2 = ('Thunder') print(storm_1 + Union + storm_2) > Lightning and Thunder
Или может быть вы хотели показать такой результат?
storm_1 = ('Lightning',) Union = (' and ',) storm_2 = ('Thunder',) print(storm_1 + Union + storm_2) > ('Lightning', ' and ', 'Thunder')
Спасибо за комментарий, код примера исправил 👌
Спасибо за объяснение! Достойно!
спасибо большое очень полезно не знала бы что делать без вас
Не согласен с последней фразой. Наоборот если не нужна изменяемость данных то следует использовать именно кортежи. Как минимум это защитит от случайного изменения данных, как максимум кортежи ещё и меньше памяти занимают.
Вывод о то, что у кортежей есть уникальные преимущества в определенных сценариях. Списки же можно использовать в любых сценариях, поэтому они чаще используются в Python.
Можно ли задать кортеж:
list_of_colors = (RED = (255, 0, 0), GREEN = (0, 255, 0))
И если да, как правильно это сделать?
Можно сделать кортеж словарей:
list_of_colors = ({"RED": (255, 0, 0)}, {"GREEN": (0, 255, 0)}) print(list_of_colors) > ({'RED': (255, 0, 0)}, {'GREEN': (0, 255, 0)})
Или использовать именованный кортеж:
from collections import namedtuple color = namedtuple("Color", "name code") list_of_colors = ( color(name='RED', code=(255, 0, 0)), color(name='GREEN', code=(0, 255, 0)) ) print(list_of_colors) > (Color(name='RED', code=(255, 0, 0)), Color(name='GREEN', code=(0, 255, 0)))
Как сделать правильно, зависит от конкретной задачи.
Топ! Коротко и по сути!