Кортежи в Python

User Rating: 5 / 5

Кортеж (англ. tuple) - это структура данных в Python, которая представляет собой определённое количество значений, разделённых запятой. Например, так создаётся кортеж с именем my_tuple:

if __name__ == '__main__':
    my_tuple = 100, 200, 300, 'это удивительно!'

Мы можем обратиться к конкретному элементу кортежа по индексу с помощью квадратных скобок [ ], внутри которых указывается индекс требуемого элемента:

if __name__ == '__main__':
    my_tuple = 100, 200, 300, 'это удивительно!'
    print(my_tuple)
    print(my_tuple[0])
    print(my_tuple[1])
    print(my_tuple[2])
    print(my_tuple[3])

При запуске скрипта на консоль будет выведено:

(100, 200, 300, "это удивительно!")
100
200
300
это удивительно!

Обратите внимание, что кортеж содержит элементы разных типов данных - в нашем случае это целые числа (тип int) и строка (тип str).

Кортежи могут быть вложенными друг в друга:

if __name__ == '__main__':
    my_tuple = 100, 200, 300, 'это удивительно!'
    print(my_tuple)
    print(my_tuple[0])
    print(my_tuple[1])
    print(my_tuple[2])
    print(my_tuple[3])

    my_complex_tuple = my_tuple, ('это', 'ещё', 'один', 'кортеж')
    print(my_complex_tuple)

В этом примере мы создаём ещё один кортеж my_complex_tuple, в который входит наш первый кортеж my_tuple и новый кортеж из четырёх строк. Запустим этот скрипт и увидим на экране консоли:

(100, 200, 300, "это удивительно!")
100
200
300
это удивительно!
((100, 200, 300, "это удивительно!"), ('это', 'ещё', 'один', 'кортеж'))

Важной особенностью кортежей является то, что они являются иммутабельными (от англ. immutable), или, проще говоря, неизменяемыми. Это означает, что при попытке изменить какой-то элемент кортежа мы получим ошибку:

if __name__ == '__main__':
    my_tuple = 100, 200, 300, 'это удивительно!'
    print(my_tuple)
    print(my_tuple[0])
    print(my_tuple[1])
    print(my_tuple[2])
    print(my_tuple[3])

    my_complex_tuple = my_tuple, ('это', 'ещё', 'один', 'кортеж')
    print(my_complex_tuple)

    my_tuple[2] = 10000     # здесь будет ошибка, поскольку кортежи неизменяемые

Попробуйте запустить скрипт, на экране будут отображены детали ошибки такого плана:

Traceback (most recent call last):
File "C:/Users/компьютер/PycharmProjects/allineed_samples/main.py", line 175, in <module>
my_tuple[2] = 10000
TypeError: 'tuple' object does not support item assignment

Мы можем также определить пустой кортеж следующим образом:

if __name__ == '__main__':
    my_empty_tuple = ()
    print(f'Мой пустой кортеж: {my_empty_tuple}')

При запуске этого скрипта на консоль будет выведено:

Мой пустой кортеж: ()

Существуют также небольшой трюк, чтобы создать кортеж из одного элемента - необходимо после значения кортежа указать запятую. Вот как это выглядит:

if __name__ == '__main__':
    t = 'это кортеж, а не строка!',   # обратите внимание на запятую в конце. именно благодаря ей t
    # становится кортежем, а не строкой

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

if __name__ == '__main__':
    t = 'это кортеж, а не строка!',   # обратите внимание на запятую в конце. именно благодаря ей t
    # становится кортежем, а не строкой
    print(f'Проверка, что t - это кортеж, а не строка. t = {t}')

В консоли будет выведено:

Проверка, что t - это кортеж, а не строка. t = ('это кортеж, а не строка!',)

Кортежи могут подвергаться так называемым операциям упаковки и распаковки. Давайте глянем, что это значит:

if __name__ == '__main__':
    t1 = 1000, 2000, 3000    # "упаковка" кортежа t1 значениями 1000, 2000 и 3000
    one, two, three = t1    # "распаковка" кортежа t1 - присваиваем переменным one, two, three значения кортежа

    print(f'Кортеж t1: {t1}')
    print(f'Распакованные значения: one={one}, two={two}, three={three}')

В этом примере мы определили кортеж t1 и "упаковали" в него значения 1000, 2000 и 3000. Точно также мы "распаковываем" кортеж в переменные one, two, three, указывая их с левой стороны от оператора присваивания, а наш кортеж t1 справа от присваивания. Важной особенностью "распаковки" кортежа является то, что обязательно нужно указать ровно столько переменных слева от оператора присваивания, сколько элементов содержится в кортеже. Если это правило не соблюсти, то мы поймаем ошибку:

if __name__ == '__main__':
    t1 = 1000, 2000, 3000    # "упаковка" кортежа t1 значениями 1000, 2000 и 3000
    one, two, three, four = t1    # неверная "распаковка" кортежа t1 - переменная four уже лишняя

При запуске скрипта увидим ошибку:

Traceback (most recent call last):
File "C:/Users/компьютер/PycharmProjects/allineed_samples/main.py", line 166, in <module>
one, two, three, four = t1 # неверная "распаковка" кортежа t1 - переменная four уже лишняя
ValueError: not enough values to unpack (expected 4, got 3)

Точно так же получим ошибку и при недостаточном количестве переменных в левой части:

if __name__ == '__main__':
    t1 = 1000, 2000, 3000    # "упаковка" кортежа t1 значениями 1000, 2000 и 3000
    a, b = t1                     # снова неверная "распаковка" кортежа t1 - переменных всего две, а не три

В этом случае при запуске будет немного другая ошибка, но тоже говорящая о том, что "распаковка" кортежа некорректна:

Traceback (most recent call last):
File "C:/Users/компьютер/PycharmProjects/allineed_samples/main.py", line 166, in <module>
a, b = t1 # снова неверная "распаковка" кортежа t1 - переменных всего две, а не три
ValueError: too many values to unpack (expected 2)

Давайте ещё рассмотрим одну интересную особенность работы с кортежами в Python. Несмотря на то, что сами кортежи являются неизменяемыми, они вполне могут содержать изменяемые элементы, например, списки. Рассмотрим следующий скрипт:

if __name__ == '__main__':
    list1 = [1, 2, 3]
    list2 = [4, 5, 6]
    list_tuple = (list1, list2, ['это', 'список', 'строк'])

    print(f'list_tuple = {list_tuple}')
    print(f'list_tuple[0] = {list_tuple[0]}')
    print(f'list_tuple[1] = {list_tuple[1]}')
    print(f'list_tuple[2] = {list_tuple[2]}')

    list1.reverse()
    list2.remove(4)

    list3 = list(list_tuple[2]);
    list3.append('ещё элемент')

    print(f'list_tuple[0] = {list_tuple[0]}')
    print(f'list_tuple[1] = {list_tuple[1]}')
    print(f'list_tuple[2] = {list_tuple[2]}')

Здесь мы упаковали в кортеж list_tuple три списка: list1, list2 и третий список без явно выделенной под него переменной и содержащий три элемента-строки: 'это', 'список', 'строк'.

Дальше мы выводим сам кортеж на экран, а также каждый его элемент. После этого мы меняем списки list1 и list2 - в первом изменяем порядок элементов на обратный, а во втором удаляем элемент 4. Также для третьего списка, хранящегося в кортеже, мы пытаемся получить его в переменную list3 и добавить новый элемент 'ещё элемент'. Вот что у нас выведется на консоль при запуске скрипта:

list_tuple = ([1, 2, 3], [4, 5, 6], ['это', 'список', 'строк'])
list_tuple[0] = [1, 2, 3]
list_tuple[1] = [4, 5, 6]
list_tuple[2] = ['это', 'список', 'строк']
list_tuple[0] = [3, 2, 1]
list_tuple[1] = [5, 6]
list_tuple[2] = ['это', 'список', 'строк']

Во втором выводе элементов кортежа мы видим, что изменения для list1 и list2 отразились на кортеже - теперь он содержит изменённые списки. А вот третий список не изменился... Как вы думаете, почему это произошло? Напишите свою версию в комментариях к статье. 

Итак, мы рассмотрели понятие кортежа в Python, его ключевые особенности и основные операции, которые можно выполнять с кортежами. Рекомендую использовать эту полезную структуру данных в ваших Python-скриптах. Уверен, она поможет решить различные интересные задачи.

Яндекс.Метрика