Методы работы с кортежами
Кортежи по функциональности похожи на списки – разберемся, когда стоит использовать кортежи вместо списков, и как обрабатывать содержащиеся в них данные. В конце статьи – 10 задач для тренировки.
Кортежи tuple
в Python предназначены, как и списки, для хранения последовательностей, состоящих из данных любого типа. Однако, в отличие от списков, кортежи относятся к неизменяемым типам данных. По этой причине в них часто хранят информацию, которую необходимо защитить от случайного изменения – например, конфигурационные данные.
Кортеж в Питоне: свойства и особенности
1. Кортежи не поддерживают добавление и удаление элементов, но допускают расширение и дополнение для тех элементов, которые относятся к изменяемым типам (списки, словари), а также любые операции с элементами элементов:
>>> numbers = ([1, 2, 3, 4], [5, 4, 5])
>>> numbers[1].extend([3, 5, 9])
>>> numbers[0].append([7, 7, 8])
>>> numbers[1][1] += 5
>>> print(numbers)
([1, 2, 3, 4, [7, 7, 8]], [5, 9, 5, 3, 5, 9])
2. Кортежи поддерживают неограниченный уровень вложенности:
numbers = ((4, 5, 8, (5, 1, (5, 3))), (7, 2, (4, 5, (3, 1, 1))))
3. Кортежи работают немного быстрее, чем списки – это связано с особенностями хранения tuple
в памяти:
>>> from timeit import timeit
>>> times = 1000000
>>> t1 = timeit("list(['груша', 'виноград','яблоко', 'банан', 'апельсин'])", number=times)
>>> t2 = timeit("tuple(('груша', 'виноград','яблоко', 'банан', 'апельсин'))", number=times)
>>> diff = "{:.0%}".format((t2 - t1)/t1)
>>> print(f'Время копирования списка {times} раз: {t1}')
Время копирования списка 1000000 раз: 0.5761922669999961
>>> print(f'Время копирования кортежа {times} раз: {t2}')
Время копирования кортежа 1000000 раз: 0.22475764600000048
>>> print(f'Разница: {diff}')
Разница: -61%
4. Кортежи занимают меньше места в памяти:
>>> from sys import getsizeof
>>> numbers1 = ((1, 2, 3, 4), (5, 4, 5))
>>> numbers2 = [[1, 2, 3, 4], [5, 4, 5]]
>>> print(getsizeof(numbers1))
36
>>> print(getsizeof(numbers2))
44
5. Кортежи поддерживают конкатенацию +
и повторение * n
:
>>> num1 = (1, 2, 3)
>>> num2 = (4, 5, 6)
>>> print(num1 + num2)
(1, 2, 3, 4, 5, 6)
>>> print(num1 * 3)
(1, 2, 3, 1, 2, 3, 1, 2, 3)
6. Элементы tuple
можно использовать в качестве значений переменных; этот прием называют распаковкой кортежа:
>>> seasons = ('весна', 'лето', 'осень', 'зима')
>>> s1, s2, s3, s4 = seasons
>>> print(s1, s3)
весна осень
Создание tuple в Питоне
Пустой кортеж можно создать двумя способами – с помощью круглых скобок ()
и с использованием функции tuple()
:
my_tuple = ()
my_tuple2 = tuple()
При создании кортежа с одним элементом после этого элемента необходимо ставить запятую, иначе Python не определяет конструкцию как кортеж:
>>> my_tuple = (5)
>>> print(type(my_tuple))
<class 'int'>
>>> my_tuple = (5,)
>>> print(type(my_tuple))
<class 'tuple'>
Создать кортеж с несколькими элементами можно следующими способами.
Способ 1: Перечисление элементов
Как и в случае со списками и словарями, кортеж с данными можно создать вручную. Кортеж может содержать данные различных типов:
info = ('Егор', 'разработчик', 350000, 28)
Элементы кортежа необязательно перечислять в круглых скобках – когда Python получает более одного значения для переменной, создание (“упаковка”) кортежа происходит автоматически:
>>> letters = 'a', 'b', 'c', 'd'
>>> print(letters)
('a', 'b', 'c', 'd')
Способ 2: Преобразование других типов данных
С помощью встроенной функции tuple()
можно создать кортеж из списка, строки или множества:
>>> my_lst = [4, 6, 2, 8]
>>> print(tuple(my_lst))
(4, 6, 2, 8)
>>> my_str = 'Я изучаю Python'
>>> print(tuple(my_str))
('Я', ' ', 'и', 'з', 'у', 'ч', 'а', 'ю', ' ', 'P', 'y', 't', 'h', 'o', 'n')
>>> my_set = {2, 5, 6, 7}
>>> print(tuple(my_set))
(2, 5, 6, 7)
Однако при подобном преобразовании словаря в кортеж останутся только ключи:
>>> my_dict = {'яблоки': 52, 'апельсины': 35}
>>> print(tuple(my_dict))
('яблоки', 'апельсины')
Число напрямую преобразовать в кортеж нельзя:
>>> num = 178394
>>> print(tuple(num))
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
TypeError: 'int' object is not iterable
Но если конвертировать число в строку, преобразование пройдет без ошибок:
>>> num = 31232534
>>> print(tuple(str(num)))
('3', '1', '2', '3', '2', '5', '3', '4')
В ходе преобразования строки в кортеж с помощью одной лишь функции tuple()
строка разбивается на отдельные символы. Если нужно разбить строку по одному разделителю, подойдет метод partition()
:
>>> st = 'Я изучаю***Python'
>>> print(st.partition('***'))
('Я изучаю', '***', 'Python')
Чтобы разбить строку по всем разделителям, вместе с tuple()
используют split()
:
>>> st = tuple(input().split())
Код на языке Python
>>> print(st)
('Код', 'на', 'языке', 'Python')
Способ 3: Генератор кортежей
Генераторы кортежей, в отличие от списков и словарей, не слишком удобно использовать для решения практических задач:
>>> my_tuple = (i for i in range(5))
>>> print(my_tuple)
<generator object <genexpr> at 0x023B5830>
Но если генератор кортежа все-таки необходимо использовать, это можно сделать двумя способами:
1. Распаковать сгенерированный объект при выводе:
>>> numbers = (i for i in range(10))
>>> print(*numbers)
0 1 2 3 4 5 6 7 8 9
2. Либо использовать в генераторе функцию tuple()
:
>>> my_tuple = tuple(i ** 2 for i in range(1, 12, 2))
>>> print(my_tuple)
(1, 9, 25, 49, 81, 121)
Способ 4: Распаковка строк и списков
Оператор распаковки *
и запятая после имени переменной автоматически превращают строки и списки в кортежи:
>>> st = 'Я изучаю Python'
>>> sp = ['Python', 'HTML5', 'CSS', 'JavaScript']
>>> tuple1 = (*st,)
>>> tuple2 = (*sp,)
>>> print(tuple1)
('Я', ' ', 'и', 'з', 'у', 'ч', 'а', 'ю', ' ', 'P', 'y', 't', 'h', 'o', 'n')
>>> print(tuple2)
('Python', 'HTML5', 'CSS', 'JavaScript')
Методы кортежей Python
Кортежи поддерживают большинство методов списков, за исключением удаления элементов и присваивания им новых значений:
>>> my_tuple = (4, 5, 6)
>>> del my_tuple[1]
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
TypeError: 'tuple' object doesn't support item deletion
>>> my_tuple[2] = 9
Traceback (most recent call last):
File "<pyshell>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
Индексация и срезы
Индексация и срезы в кортежах работают так же, как и в списках:
>>> my_tuple = ('банан', 'груша', 'манго')
>>> print(my_tuple[0], my_tuple[-1])
банан манго
>>> print(my_tuple[1:])
('груша', 'манго')
>>> print(my_tuple[::-1])
('манго', 'груша', 'банан')
Для возвращения индексa элемента используется index()
:
>>> nutr = ('белки', 'жиры', 'углеводы')
>>> print(nutr.index('белки'))
0
Длина, сумма, минимальный и максимальный элементы
Эти методы тоже аналогичны списочным:
>>> my_tuple = ('карандаш', 'ручка', 'шар')
>>> print(len(my_tuple))
3
>>> print(min(my_tuple, key=len))
шар
>>> print(max(my_tuple, key=len))
карандаш
>>> nums = (4, 5, 2, 1, 6)
>>> print(sum(nums))
18
Принадлежность
С помощью операторовin
и not in
можно убедиться в наличии (отсутствии) определенного значения в кортеже:
>>> nums = (1, 3, 5, 6, 7, 8)
>>> (5 in nums)
True
>>> (25 not in nums)
True
Подсчет элементов
Для подсчета числа вхождений какого-либо значения в кортеже используется count()
:
>>> cities = ('Москва', 'Ростов', 'Москва', 'Рязань', 'Саратов', 'Москва')
>>> print(cities.count('Москва'))
3
Сортировка
Кортежи поддерживают сортировку, однако результатом будет список:
>>> nums = (4, 1, 7, 2, 0, 9, 5)
>>> print(sorted(nums))
[0, 1, 2, 4, 5, 7, 9]
Если результат должен сохраняться в виде кортежа, нужно использовать tuple()
:
>>> nums = (4, 1, 7, 2, 0, 9, 5)
>>> print(tuple(sorted(nums, reverse=True)))
(9, 7, 5, 4, 2, 1, 0)
Преобразование кортежей в другие типы данных
Кортеж можно преобразовать в строку:
>>> letters = ('P', 'y', 't', 'h', 'o', 'n')
>>> print('*'.join(letters))
P*y*t*h*o*n
В список:
>>> sp = (2, 7, 5, 8, 1)
>>> print(list(sp))
[2, 7, 5, 8, 1]
В словарь (если кортеж вложенный и состоит из пар значений):
>>> info = (('фрукты', 5), ('овощи', 15), ('конфеты', 3))
>>> print(dict(info))
{'фрукты': 5, 'овощи': 15, 'конфеты': 3}
Во множество:
>>> numbers = (3, 2, 1, 6, 7, 2, 2, 9)
>>> print(set(numbers))
{1, 2, 3, 6, 7, 9}
Сравнение кортежей
Как и списки, кортежи с однородными данными можно сравнивать между собой с помощью операторов >
, >=
, <
, <=
, ==
, !=
. Если элементы кортежей принадлежат к разным типам данных, поддерживаются только операторы ==
и !=
.
>>> tuple1 = (1, 2, 3)
>>> tuple2 = (4, 5, 6)
>>> print(tuple1 < tuple2)
True
>>> print(tuple1 != tuple2)
True
Практика
Задание 1
Напишите программу, которая:
- Создает кортежи из положительных и отрицательных целых чисел на основе полученной от пользователя строки.
- Выводит количество положительных и отрицательных чисел в этих кортежах.
Пример ввода:
45 -6 -9 43 23 5 2 -9 -1 6 3
Вывод:
Кортеж (45, 43, 23, 5, 2, 6, 3) состоит из 7 положительных чисел
Кортеж (-6, -9, -9, -1) состоит из 4 положительных чисел
Решение:
numbers = tuple(map(int, input().split()))
pos = tuple(i for i in numbers if i > 0)
neg = tuple(i for i in numbers if i < 0)
print(f'Кортеж {pos} состоит из {len(pos)} положительных чисел')
print(f'Кортеж {neg} состоит из {len(neg)} положительных чисел')
Задание 2
Напишите программу, которая:
- Создает кортеж из полученной от пользователя строки, состоящей из вещественных чисел, разделенных пробелами.
- Выводит минимальный и максимальный элементы кортежа, а также их сумму.
Пример ввода:
3.45 6.78 8.99 1.45 4.32 19.04 0.55
Вывод:
Минимальное число: 0.55
Максимальное число: 19.04
Сумма min и max: 19.59
Решение:
my_tuple = tuple(map(float, input().split()))
print(f'Минимальное число: {min(my_tuple)}')
print(f'Максимальное число: {max(my_tuple)}')
print(f'Сумма min и max: {((min(my_tuple) + max(my_tuple))):.2f}')
Задание 3
Имеется кортеж списков, в которых перечислены названия фруктов и калорийность:
fruit = (['яблоки', 46], ['персики', 49], ['лимоны', 36], ['виноград', 190])
Калорийность винограда указана ошибочно. Напишите программу, которая исправит калорийность на 75
, и добавит в третий элемент кортежа новое значение ['айва', 42]
. Результат должен выглядеть так:
fruit = (['яблоки', 46], ['персики', 49], ['лимоны', 36, 'айва', 42], ['виноград', 75])
Решение:
fruit = (['яблоки', 46], ['персики', 49], ['лимоны', 36], ['виноград', 190])
fruit[3][1] = 75
fruit[2].extend(['айва', 42])
print(fruit)
Задание 4
Имеется вложенный кортеж:
numbers = ((5, 4, 5, 4), (3, 3, 4, 6), (8, 9, 5, 4), (12, 4, 5, 1), (9, 3, 5, 1))
Напишите программу, которая формирует новый кортеж, состоящий из средних арифметических значений элементов numbers
. Результат выводится в следующем виде:
4.5 4.0 6.5 5.5 4.5
Решение:
numbers = ((5, 4, 5, 4), (3, 3, 4, 6), (8, 9, 5, 4), (12, 4, 5, 1), (9, 3, 5, 1))
avg = tuple(sum(i)/len(i) for i in numbers)
print(*avg)
Задание 5
Имеется вложенный кортеж:
nested_tuple = ((12, 3, 1), (5, 11), (15, 7, 8, 9), (10, 6, 4))
Напишите программу для преобразования nested_tuple в обычный кортеж, упорядоченный по возрастанию:
(1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15)
Решение:
nested_tuple = ((12, 3, 1), (5, 11), (15, 7, 8, 9), (10, 6, 4))
res = []
flat_list = [res.extend(i) for i in nested_tuple]
print(tuple(sorted(res)))
Задание 6
Напишите программу для сортировки вложенного кортежа по третьему элементу. Исходный кортеж:
(('красный', 33, 55), ('зеленый', 17, 44), ('синий', 12, 3), ('черный', 2, 5))
Результат:
(('черный', 2, 5), ('синий', 12, 3), ('зеленый', 17, 44), ('красный', 33, 55))
В качестве ключа сортировки следует использовать конструкцию key=lambda x: x[2]
– это анонимная функция. В последующих статьях мы будем подробно разбирать применение анонимных функций.
Решение:
nested_tuple = (('красный', 33, 55), ('зеленый', 17, 44), ('синий', 12, 3), ('черный', 2, 5))
nested_tuple = tuple(sorted(list(nested_tuple), key=lambda x: x[2]))
print(nested_tuple)
Задание 7
Напишите программу, которая:
- принимает на вход строку, состоящую из цифр или символов, разделенных пробелами;
- создает из строки кортеж;
- проверяет, состоит ли кортеж из одинаковых элементов;
- выводит
True
илиFalse
в зависимости от результатов проверки.
Для проверки соответствия всех элементов одному условию в Python используется встроенная функция all():
all(i == my_tuple[0] for i in my_tuple)
Пример ввода:
35 35 35 35 35
Вывод:
True
Решение:
my_tuple = tuple(input().split())
print(all(i == my_tuple[0] for i in my_tuple))
Задание 8
Напишите программу, которая на основе исходного кортежа создает новый кортеж, из которого исключены все пользователи с номерами телефонов с региональным кодом +56.
Исходный кортеж:
info = (('Евгений Романов', 25, '+56(983)354-67-21'),
('Марина Дятлова', 22, '+56(190)251-45-79'),
('Кирилл Кудрявцев', 34, '+7(890)456-12-42'),
('Сергей Дятлов', 24, '+56(190)156-42-99'),
('Юлия Степанова', 21, '+16(398)355-33-09'),
('Тимофей Иванов', 34, '+7(918)222-52-77'))
Ожидаемый результат:
(('Кирилл Кудрявцев', 34, '+7(890)456-12-42'), ('Юлия Степанова', 21, '+16(398)355-33-09'), ('Тимофей Иванов', 34, '+7(918)222-52-77'))
Решение:
info = (('Евгений Романов', 25, '+56(983)354-67-21'),
('Марина Дятлова', 22, '+56(190)251-45-79'),
('Кирилл Кудрявцев', 34, '+7(890)456-12-42'),
('Сергей Дятлов', 24, '+56(190)156-42-99'),
('Юлия Степанова', 21, '+16(398)355-33-09'),
('Тимофей Иванов', 34, '+7(918)222-52-77'))
new_info = tuple([i for i in info if not i[2].startswith('+56')])
print(new_info)
Задание 9
Имеется кортеж списков:
numbers = ([4, 5], [4, 5], [1, 6], [7, 3], [3, 3], [2, 4], [9, 5], [1, 1])
Напишите программу, которая добавит цифру 5
в конец каждого списка.
Ожидаемый результат:
numbers = ([4, 5, 5], [4, 5, 5], [1, 6, 5], [7, 3, 5], [3, 3, 5], [2, 4, 5], [9, 5, 5], [1, 1, 5])
Решение:
numbers = ([4, 5], [4, 5], [1, 6], [7, 3], [3, 3], [2, 4], [9, 5], [1, 1])
add = [i.extend([5]) for i in numbers]
print(numbers)
Задание 10
Напишите программу, которая:
- получает на вход целое число n – количество точек на плоскости;
- получает n строк с координатами
x, y
; - определяет точку, наиболее удаленную от начала координат.
Пример ввода:
5
4 8
1 2
7 4
7 8
3 2
Вывод:
7 8
Решение:
n = int(input())
points = [tuple(map(int, input().split())) for i in range(n)]
mx = max(points, key=lambda x: x[0] ** 2 + x[1] ** 2)
print(*mx)
Подведем итоги
Кортежи во многом похожи на списки. Выбор в пользу кортежей стоит делать тогда, когда необходимо защитить данные от случайного изменения. Кроме того, многие операции с кортежами выполняются быстрее и занимают меньше памяти. В следующей статье будем изучать множества.