Все курсы > Программирование на Питоне > Занятие 7
На сегодняшнем занятии мы подробнее поговорим про три структуры данных в Питоне: списки, кортежи и множества. Каждая из них относится к так называемым коллекциям (collections), то есть структурам, содержащим сразу несколько элементов. При этом у каждой есть свои важные особенности.
Вначале откроем ноутбук к этому занятию⧉
Списки
Мы начали изучать списки на пятом занятии вводного курса. Продолжим эту работу.
Основы работы со списками
Список можно создать (или как правильнее говорить инициализировать) через пустые квадратные скобки [] или с помощью функции list().
1 2 3 4 |
some_list_1 = [] some_list_2 = list() print(some_list_1, some_list_2) |
1 |
[] [] |
Элементом списка может быть любой объект, например, число, строка, список или словарь.
1 2 |
number_three = [3, 'число три', ['число', 'три'], {'число': 3}] number_three |
1 |
[3, 'число три', ['число', 'три'], {'число': 3}] |
Длину списка можно узнать с помощью функции len().
1 |
len(number_three) |
1 |
4 |
Индекс и срез списка
Как мы уже знаем, у списка есть индекс. Элементы списка индексируются так же, как символы в строке.

1 2 3 4 5 |
# создадим список из букв abc_list = ['a', 'b', 'c', 'd', 'e'] # выведем первый и последний элементы print(abc_list[0], abc_list[-1]) |
1 |
a e |
Рассмотрим пример со вложенными списками (nested list). Для того чтобы обратиться, например, к первому элементу второго вложенного списка нужно использовать двойной индекс [1][0].
1 2 |
salary_list = [['Анна', 90000], ['Игорь', 85000], ['Алексей', 95000]] salary_list[1][0] |
1 |
'Игорь' |
Обратите внимание, мы начали с индекса вложенного списка ['Игорь', 85000] в общем списке salary_list (как бы снаружи). Он соответствует [1]. Затем мы указали индекс первого элемента внутри вложенного списка [0].
Индекс элемента в списке можно узнать с помощью метода .index(). Предположим, мы хотим узнать индекс элемента 'c' в списке abc_list.
1 |
abc_list.index('c') |
1 |
2 |
Метод .index() можно применить ко вложенному списку.
1 2 |
# возьмем первый [0] список ['Анна', 90000] и выясним индекс уровня зарплаты salary_list[0].index(90000) |
1 |
1 |
В случае если мы хотим получить срез списка, то так же как и в случае строк, мы указываем начало среза и элемент до которого (но не включая который) сделать срез.
1 2 |
days_list = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'] days_list[1:5] |
1 |
['Вт', 'Ср', 'Чт', 'Пт'] |
У среза есть третий параметр — шаг. Он позволяет пропускать заданное количество элементов.
1 2 |
# начнем с Пн и будем брать дни через один вплоть до, но не включая, Сб [5] days_list[:5:2] |
1 |
['Пн', 'Ср', 'Пт'] |
Кроме того, мы можем проверить содержится ли элемент в списке с помощью ключевого слова in.
1 |
'Пн' in days_list |
1 |
True |
1 2 |
if 'Вт' in days_list: print('Такое слово есть') |
1 |
Такое слово есть |
Добавление, замена и удаление элементов списка
Мы уже умеем использовать метод .append(), который добавляет элемент в конец списка.
1 2 3 4 |
weekdays = ['Понедельник', 'Вторник'] weekdays.append('Четверг') weekdays |
1 |
['Понедельник', 'Вторник', 'Четверг'] |
Метод .insert() позволяет добавить элемент в середину списка, при этом индекс последующих элементов сдвигается.
1 2 3 4 |
# для этого методу .insert() мы передаем желаемый индекс нового элемента # и сам этот элемент weekdays.insert(2, 'Среда') weekdays |
1 |
['Понедельник', 'Вторник', 'Среда', 'Четверг'] |
Элемент списка можно заменить по индексу.
1 2 |
weekdays[3] = 'Пятница' weekdays |
1 |
['Понедельник', 'Вторник', 'Среда', 'Пятница'] |
Элемент можно удалить, указав либо его название, либо индекс.
1 2 3 |
# для удаления по названию можно использовать метод .remove() weekdays.remove('Пятница') weekdays |
1 |
['Понедельник', 'Вторник', 'Среда'] |
1 2 3 |
# ключевое слово del удаляет элемент по индексу del(weekdays[2]) weekdays |
1 |
['Понедельник', 'Вторник'] |
1 2 3 |
# метод .pop() не просто удаляет элемент по индексу # но и выводит удаляемый элемент weekdays.pop(1) |
1 |
'Вторник' |
Все эти операции возможны благодаря тому, что списки (1) упорядочены и (2) изменяемы.
Убедимся, что остался только понедельник.
1 |
weekdays |
1 |
['Понедельник'] |
Сложение списков
Добавить к списку еще один список можно с помощью метода .extend(). Мы с вами уже использовали его на занятии по обработке естественного языка.
1 2 3 4 5 |
# добавим к списку, в котором есть только понедельник, остальные дни more_weekdays = ['Вторник', 'Среда', 'Четверг', 'Пятница'] weekdays.extend(more_weekdays) weekdays |
1 |
['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница'] |
Кроме того, два списка можно просто сложить (concatenate).
1 2 3 |
# прибавим выходные weekend = ['Суббота', 'Воскресенье'] print(weekdays + weekend) |
1 |
['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'] |
Добавлю, что иногда бывает полезно «размножить» элементы списка.
1 2 3 |
# для этого элемент в квадратных скобках нужно умножить на # желаемую длину списка ['Понедельник'] * 2 |
1 |
['Понедельник', 'Понедельник'] |
Такие «произведения» также можно складывать.
1 |
['Понедельник'] * 2 + ['Вторник'] * 2 |
1 |
['Понедельник', 'Понедельник', 'Вторник', 'Вторник'] |
Распаковка списков
Ранее мы уже познакомились с возможностью распаковки списков (unpacking), то есть помещения элементов списка в переменные. Теперь посмотрим на этот функционал более внимательно.
1 2 |
# заново создадим список с днями недели week = ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'] |
Во-первых, элемент можно вывести по индексу и поместить в переменную.
1 2 |
Mon = week[0] Mon |
1 |
'Понедельник' |
Несколько элементов можно поместить сразу в несколько переменных. Количество передаваемых элементов можно регулировать срезом.
1 2 3 |
# количество переменных должно быть равно количеству элементов среза Mon, Tue, Wed = week[:3] Mon, Tue, Wed |
1 |
('Понедельник', 'Вторник', 'Среда') |
Если нас интересует только первый элемент списка, но мы не хотим использовать индекс, можно распаковать список в две переменные, пометив вторую символом *. В первую попадет первый элемент, во вторую — все остальные.
1 2 3 4 5 |
# в переменную _ попадут дни со вторника по воскресенье Mon, *_ = week # в Mon - только понедельник Mon |
1 |
'Понедельник' |
Аналогичным образом мы можем распаковать первый, *остальные и последний элементы списка.
1 2 3 |
# в days попадут дни со вторника по субботу Mon, *days, Sun = week Mon, Sun |
1 |
('Понедельник', 'Воскресенье') |
Сортировка списков
Для сортировки списка можно использовать функцию sorted() и метод .sort(). Функция sorted() не изменяет объект и сразу выводит результат сортировки.
1 2 3 |
# отсортируем список по возрастанию nums = [25, 10, 30, 20, 5, 15] sorted(nums) |
1 |
[5, 10, 15, 20, 25, 30] |
1 2 |
# исходный список остается прежним nums |
1 |
[25, 10, 30, 20, 5, 15] |
Впрочем, если записать результат вызова функции sorted() в переменную, изменение станет постоянным.
1 2 |
sorted_nums = sorted(nums) sorted_nums |
1 |
[5, 10, 15, 20, 25, 30] |
Метод .sort() изменяет сам объект, но результат сортировки нужно вывести отдельно.
1 2 3 |
# с помощью параметра reverse = True сортируем список по убыванию nums.sort(reverse = True) nums |
1 |
[30, 25, 20, 15, 10, 5] |
Метод .reverse() задает обратный порядок элементов списка (объект также изменяется, результат по умолчанию не выводится).
1 2 |
nums.reverse() nums |
1 |
[5, 10, 15, 20, 25, 30] |
Преобразование списка в строку
Мы с вами уже умеем разбивать строку на части и превращать в список. Иногда бывает полезно сделать обратное.
Возьмем список, состоящий из букв.
1 |
str_list = ['P', 'y', 't', 'h', 'o', 'n'] |
И преобразуем его в строку с помощью метода .join(). Обратите внимание, пространство между элементами списка мы ничем не заполняем и для этого оставляем кавычки пустыми ''.
1 2 |
joined_str = ''.join(str_list) joined_str |
1 |
'Python' |
Конечно, мы можем указать любой другой межбуквенный элемент.
1 2 |
joined_str_ = '_'.join(str_list) joined_str_ |
1 |
'P_y_t_h_o_n' |
Арифметика в списках
Вновь создадим список, состоящий из чисел.
1 |
nums_ = [3, 2, 1, 4, 5, 12, 3, 3, 7, 9, 11, 15] |
С помощью метода .count() мы можем посчитать частоту вхождения элемента в список.
1 2 |
# посмотрим, сколько раз число три встречается в нашем списке nums_.count(3) |
1 |
3 |
Функции min(), max() и sum() позволяют рассчитать минимальное и максимальное значение, а также сумму элементов списка.
1 |
print(min(nums_), max(nums_), sum(nums_)) |
1 |
1 15 75 |
List comprehension
А теперь рассмотрим list comprehension. По сути, list comprehension позволяет превратить один список в другой, преобразовывая и отбирая элементы исходного списка.

Рассмотрим на примерах. Предположим, у нас есть список имен.
1 |
names = ['Артем', 'Антон', 'Александр', 'Борис', 'Виктор', 'Геннадий'] |
И на основе этого списка мы хотим создать новый список, в котором останутся только имена, начинающиеся с буквы «А». Очевидно, мы можем использовать цикл for.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# создадим пустой список a_names a_names = [] # пройдемся по списку имен for name in names: # если имя начинается с 'А' if name.startswith('А'): # добавим его в список a_names a_names.append(name) # посмотрим на результат a_names |
1 |
['Артем', 'Антон', 'Александр'] |
List comprehension позволяет сделать то же самое, но в одну строку.
1 2 |
a_names = [name for name in names if name.startswith('А')] a_names |
1 |
['Артем', 'Антон', 'Александр'] |
Немного изменив код, мы можем перевести все заглавные буквы имен исходного списка в строчные.
1 2 |
lower_names = [name.lower() for name in names] lower_names |
1 |
['артем', 'антон', 'александр', 'борис', 'виктор', 'геннадий'] |
На основе этих двух примеров давайте разберемся с синтаксисом list comprehension.

- Вначале идет выражение, преобразующее каждый элемент исходного списка.
- Если просто указать переменную, как это было в первом примере с переменной name, элементы перейдут из исходного списка в новый без изменений.
- Во втором примере, мы изменили регистр с заглавной буквы на строчную с помощью метода .lower().
- Затем идет блок, по сути, повторяющий цикл for.
- И наконец, если это необходимо, условие c if, с помощью которого мы можем отобрать не все, а лишь некоторые из элементов исходного списка.
Приведу еще один пример.
1 2 |
replace_name = [name if name != 'Виктор' else 'Вадим' for name in names] replace_name |
1 |
['Артем', 'Антон', 'Александр', 'Борис', 'Вадим', 'Геннадий'] |
Как вы видите, здесь схема немного изменилась. Интерпретировать эту запись можно следующим образом:
- name if name != 'Виктор' — оставь элемент в списке без изменений, если он не совпадает с именем «Виктор»
- else 'Вадим' — в противном случае (т.е. если совпадает), замени на Вадим
- for name in names — сделай все это, проходясь по элементам исходного списка
Также напомню, что мы уже использовали list comprehension на занятии по обработке естественного языка. Мы брали список слов после лемматизации.
1 |
lemmatized = ['paris', 'visited', 'lot', 'museum', 'first', 'went', 'louvre', 'largest', 'art', 'museum', 'world', 'always', 'interested', 'art', 'spent', 'many', 'hour', 'museum', 'enourmous', 'week', 'would', 'enough'] |
И применяли стеммер к каждому из элементов списка с помощью list comprehension.
1 2 3 4 5 6 7 8 9 |
# импортируем класс стеммера Портера from nltk.stem import PorterStemmer # и создаем объект этого класса porter = PorterStemmer() # применяем метод .stem() к каждому слову с помощью list comprehension stemmed_p = [porter.stem(s) for s in lemmatized] print(stemmed_p) |
1 |
['pari', 'visit', 'lot', 'museum', 'first', 'went', 'louvr', 'largest', 'art', 'museum', 'world', 'alway', 'interest', 'art', 'spent', 'mani', 'hour', 'museum', 'enourm', 'week', 'would', 'enough'] |
Кортежи
Кортеж (tuple) инициализируется при помощи круглых скобок () или функции tuple().
1 2 3 |
# создадим две переменные и поместим в них пустые кортежи tuple_1, tuple_2 = (), tuple() print(tuple_1, tuple_2) |
1 |
() () |
Во многом кортеж похож на список. Это также упорядоченный набор элементов с индексом, начинающимся с нуля.
1 2 3 4 5 |
# создадим кортеж letters = ('a', 'b', 'c') # и выведем его первый элемент letters[0] |
1 |
'a' |
Основное отличие от списка — кортеж неизменяем. После того как кортеж создан, добавлять или удалять элементы нельзя.
Например, заменить элемент по его индексу нельзя.
1 2 |
# попробуем заменить первый элемент кортежа letters[0] = 'd' |

Для этого придется вначале преобразовать кортеж в список.
1 2 3 4 5 6 |
# преобразуем кортеж в список через функцию list() letters = list(letters) # теперь элементы можно изменять letters[0] = 'd' letters |
1 |
['d', 'b', 'c'] |
Создать кортеж из одного элемента можно с помощью запятой.
1 2 |
let_a = ('a', ) type(let_a) |
1 |
tuple |
Если запятую не ставить, получится строка.
1 2 |
let_a = ('a') type(let_a) |
1 |
str |
Функция enumerate()
Если с функцией enumerate() использовать не две, как мы делали раньше, а одну переменную, результатом ее работы будет кортеж, состоящий из индекса и соответствующего элемента списка.
1 2 3 4 5 6 7 |
# создадим список с названием трех компаний companies = ['Microsoft', 'Apple', 'Tesla'] # и в цикле поместим результат работы функции enumerate() # в одну переменную company for company in enumerate(companies): print(company, type(company)) |
1 2 3 |
(0, 'Microsoft') <class 'tuple'> (1, 'Apple') <class 'tuple'> (2, 'Tesla') <class 'tuple'> |
Просмотр элементов словаря
Аналогично, если в цикле for к словарю применить знакомый нам метод .items() и использовать только одну переменную, мы получим кортежи из ключа и значения.
1 2 |
# возьмем уже знакомый нам по вводному курсу словарь с овощами shopping_dict = {'огурцы': 2, 'помидоры': 3, 'лук': 1, 'картофель': 2} |
1 2 3 4 |
# пройдемся по ключам и значениям с помощью метода .items(), # но поместим результат в одну переменную item for item in shopping_dict.items(): print(item) |
1 2 3 4 |
('огурцы', 2) ('помидоры', 3) ('лук', 1) ('картофель', 2) |
Распаковка кортежей
Распаковать кортеж значит поместить каждый из его элементов в отдельную переменную.
1 2 3 4 5 |
# если в кортеже три элемента, то и переменных должно быть три a, b, c = ('a', 'b', 'c') # выведем переменную a print(a) |
1 |
a |
Кортежи удобно распаковывать в цикле for.
1 2 3 4 5 6 |
# снова возьмем список компаний companies = ['Microsoft', 'Apple', 'Tesla'] # однако с функцией enumerate() используем две переменных for i, company in enumerate(companies): print(i, company) |
1 2 3 |
0 Microsoft 1 Apple 2 Tesla |
С элементами словаря получается то же самое.
1 2 3 4 5 |
shopping_dict = {'огурцы': 2, 'помидоры': 3, 'лук': 1, 'картофель': 2} # используем две переменных с методом .items() for k, v in shopping_dict.items(): print(k, v) |
1 2 3 4 |
огурцы 2 помидоры 3 лук 1 картофель 2 |
Здесь на самом деле ничего нового для нас нет.
Создание кортежа через функцию zip()
Функция zip() принимает два и более списков и формирует объект из кортежей. В первом кортеже содержатся первые элементы каждого из списков, во втором — вторые и так далее.

1 2 3 4 5 6 |
# создадим два списка, список имен и список доходов names = ['Артем', 'Антон', 'Александр', 'Борис', 'Виктор', 'Геннадий'] income = [97000, 110000, 95000, 84000, 140000, 120000] # передадим эти списки функции zip() zip(names, income) |
1 |
<zip at 0x7f5ac5d43c30> |
Получившийся zip-объект нужно преобразовать в список.
1 |
list(zip(names, income)) |
1 2 3 4 5 6 |
[('Артем', 97000), ('Антон', 110000), ('Александр', 95000), ('Борис', 84000), ('Виктор', 140000), ('Геннадий', 120000)] |
Множества
Про множества важно запомнить три факта:
- Элементы множества изменять нельзя
- Множество — это набор уникальных элементов, а значит повторы в нем удаляются
- У множества нет индекса, элементы не упорядочены
Создание множества
Множество можно создать с помощью функции set() или перечислив элементы в фигурных скобках {}.
1 2 3 4 5 6 7 8 |
# создадим одно пустое set_1 = set() # и два непустых множества с повторяющимся элементом 'c' set_2 = set(['a', 'b', 'c', 'c']) set_3 = {'a', 'b', 'c', 'c'} print(set_1, set_2, set_3) |
1 |
set() {'c', 'b', 'a'} {'c', 'b', 'a'} |
Обратите внимание, Питон вывел элементы множества не в том порядке, в котором они были изначально записаны, и кроме того удалил повторяющийся элемент 'c'.
Это опять же говорит об уникальности и неупорядоченности элементов множества.
Пустыми фигурные скобки оставлять нельзя. Это способ создания словаря.
1 2 |
not_a_set = {} type(not_a_set) |
1 |
dict |
Добавление и удаление элементов
Как уже было сказано, изменять элементы множества нельзя. При этом нам ничто не мешает их добавлять или удалять. Предположим, мы начали создавать множество гласных букв в русском языке.
1 |
vowels = {'а', 'о', 'э', 'е', 'у', 'ё', 'ю'} |
Метод .add() позволяет добавить элемент во множество. Например, букву «я».
1 2 |
vowels.add('я') vowels |
1 |
{'а', 'е', 'о', 'у', 'э', 'ю', 'я', 'ё'} |
Несколько элементов можно добавить с помощью метода .update().
1 2 3 |
# передадим методу .update() список из двух гласных букв vowels.update(['и', 'ы']) vowels |
1 |
{'а', 'е', 'и', 'о', 'у', 'ы', 'э', 'ю', 'я', 'ё'} |
Если мы по ошибке добавим согласную букву, например, «щ».
1 2 |
vowels.add('щ') vowels |
1 |
{'а', 'е', 'и', 'о', 'у', 'щ', 'ы', 'э', 'ю', 'я', 'ё'} |
Ее можно удалить с помощью метода .remove().
1 2 |
vowels.remove('щ') vowels |
1 |
{'а', 'е', 'и', 'о', 'у', 'ы', 'э', 'ю', 'я', 'ё'} |
Теория множеств в Питоне
Разумеется, объект множества в Питоне согласуется с математической теорией множеств (set theory).
Основные понятия
В частности, мы знаем, что равные множества — это множества, состоящие из одних и тех же элементов (при этом порядок элементов не важен). Питон позволяет это проверить.
1 |
{'a', 'b', 'c'} == {'c', 'b', 'a'} |
1 |
True |
Мощность множества или его кардинальное число отражает количество элементов множества и рассчитывается с помощью знакомой нам функции len().
1 |
len({'a', 'b', 'c'}) |
1 |
3 |
Мы также можем проверить принадлежность элемента определенному множеству.
1 |
'a' in {'a', 'b', 'c'} |
1 |
True |
1 |
'a' not in {'a', 'b', 'c'} |
1 |
False |
Подмножество и надмножество
Одно множество, назовем его A, называется подмножеством (subset) другого множества B, если все элементы множества A также принадлежат и множеству B. Питон позволяет это проверить с помощью метода .issubset().
1 2 3 4 |
set_A = {'a', 'b', 'c'} set_B = {'a', 'b', 'c', 'd', 'e', 'f'} set_A.issubset(set_B) |
1 |
True |
Множество B называется надмножеством (superset) A, если A является подмножеством B. По сути, это обратная логическая операция, для которой есть метод .issuperset().
1 |
set_B.issuperset(set_A) |
1 |
True |
Объединение, пересечение и разность множеств
Теперь давайте поговорим про объединение, пересечение и разность множеств. Предположим, у нас есть две команды инженеров машинного обучения, одна занимается обработкой естественного языка (nlp), другая — компьютерным зрением (cv). Некоторые занимаются и тем, и другим.
1 2 |
nlp = set(['Анна', 'Николай', 'Павел', 'Оксана']) cv = set(['Николай', 'Евгений', 'Ольга', 'Оксана']) |
Объединение множеств (union) отражает логическую операцию ИЛИ и нашем случае мы выберем тех специалистов, которые состоят хотя бы в одной команде. Другими словами, принадлежат или одному, или другому множеству, или обоим сразу.
1 2 |
print(nlp.union(cv)) print(nlp | cv) |
1 2 |
{'Ольга', 'Оксана', 'Анна', 'Николай', 'Евгений', 'Павел'} {'Ольга', 'Оксана', 'Анна', 'Николай', 'Евгений', 'Павел'} |
Как мы видим есть два способа задать объединение множеств: через метод .union() или с помощью символа |. Аналогичные возможности есть и для других операций с множествами.
На диаграмме Эйлера это будут и те, кто входит в круг cv, и те, кто входит в nlp, и их пересечение.

При пересечении множеств (intersection) осуществляется логическая операция И. Мы выбираем только тех людей, которые работают в обеих командах, т.е. принадлежат обоим множествам.
1 2 |
print(nlp.intersection(cv)) print(nlp & cv) |
1 2 |
{'Николай', 'Оксана'} {'Николай', 'Оксана'} |
На кругах Эйлера это опять же пересечение.

Разность множеств (difference) nlp и cv позволяет увидеть, кто в команде по обработке естественного языка занимается только этой областью, и не учавствует в проектах по компьютерному зрению.
1 2 |
print(nlp.difference(cv)) print(nlp - cv) |
1 2 |
{'Павел', 'Анна'} {'Павел', 'Анна'} |

И наоборот, если мы смотрим на разность cv и nlp, то оставляем только тех, кто специализируется на компьютерном зрении.
1 2 |
print(cv.difference(nlp)) print(cv - nlp) |
1 2 |
{'Евгений', 'Ольга'} {'Евгений', 'Ольга'} |

Наконец, симметричная разность (symmetric difference) множеств объединяет обе предыдущие операции разности.
1 2 |
print(nlp.symmetric_difference(cv)) print(nlp ^ cv) |
1 2 |
{'Ольга', 'Анна', 'Евгений', 'Павел'} {'Ольга', 'Анна', 'Евгений', 'Павел'} |
Другими словами, мы видим только тех специалистов, которые заняты исключительно в одной из областей, но не в двух одновременно.

Подведем итог
Мы подробно рассмотрели три относящихся к коллекциям структуры данных, а именно списки, кортежи и множества.
Списки изменяемы и упорядочены. Кортежи упорядочены, но не изменяемы. Множества не упорядочены и не изменяемы. Кроме того, множества всегда содержат только уникальные элементы, повторы не допускаются.
Вопросы для закрепления
Как вывести элемент вложенного списка по его индексу?
Посмотреть правильный ответ
Ответ: вначале нужно указать индекс вложенного списка, а затем индекс элемента внутри этого вложенного списка.
Как выглядит основная схема list comprehension?
Посмотреть правильный ответ
Ответ: что делать с элементом : цикл for : при каком условии if. Обратите внимание, если мы хотим использовать if-else схема отличается (см. пример выше).
Что такое симметричная разность двух множеств?
Посмотреть правильный ответ
Ответ: симметричная разность двух множеств включает элементы двух множеств, не являющихся для них общими.
В ноутбуке к лекции приведены дополнительные упражнения⧉.
На следующем занятии мы поговорим про словари в Питоне и на этом завершим разбор коллекций.