Алгоритмизация и программирование/ лекция 2

Содержание

Слайд 2

План Область видимости переменных Модули Обработка исключений Списки Кортежи

План

Область видимости переменных
Модули
Обработка исключений
Списки
Кортежи

Слайд 3

Область видимости переменных Область видимости или scope определяет контекст переменной, в

Область видимости переменных

Область видимости или scope определяет контекст переменной, в рамках

которого ее можно использовать. В Python есть два типа контекста: глобальный и локальный.
Слайд 4

Область видимости переменных Глобальный контекст подразумевает, что переменная является глобальной, она

Область видимости переменных

Глобальный контекст подразумевает, что переменная является глобальной, она определена

вне любой из функций и доступна любой функции в программе. Например:
Слайд 5

Область видимости переменных Здесь переменная name является глобальной и имеет глобальную

Область видимости переменных

Здесь переменная name является глобальной и имеет глобальную область

видимости. И обе определенные здесь функции могут свободно ее использовать.
Слайд 6

Область видимости переменных В отличие от глобальных переменных локальная переменная определяется

Область видимости переменных

В отличие от глобальных переменных локальная переменная определяется внутри

функции и доступна только из этой функции, то есть имеет локальную область видимости:
Слайд 7

Область видимости переменных В данном случае в каждой из двух функций

Область видимости переменных

В данном случае в каждой из двух функций определяется

локальная переменная name. И хотя эти переменные называются одинаково, но тем не менее это дву разных переменных, каждая из которых доступна только в рамках своей функции. Также в функции say_hi определена переменная surname, которая также является локальной, поэтому в функции say_bye мы ее использовать не сможем.
Слайд 8

Область видимости переменных Есть еще один вариант определения переменной, когда локальная

Область видимости переменных

Есть еще один вариант определения переменной, когда локальная переменная

скрывают глобальную с тем же именем.
Слайд 9

Область видимости переменных Здесь определена глобальная переменная name. Однако в функции

Область видимости переменных

Здесь определена глобальная переменная name. Однако в функции say_bye

определена локальная переменная с тем же именем name. И если функция say_hi использует глобальную переменную, то функция say_bye использует локальную переменную, которая скрывает глобальную.
Слайд 10

Область видимости переменных Если же мы хотим изменить в локальной функции

Область видимости переменных

Если же мы хотим изменить в локальной функции глобальную

переменную, а не определить локальную, то необходимо использовать ключевое слово global:
Слайд 11

Область видимости переменных В Python, как и во многих других языках

Область видимости переменных

В Python, как и во многих других языках программирования,

не рекомендуется использовать глобальные переменные. Единственной допустимой практикой является определение небольшого числа глобальных констант, которые не изменяются в процессе работы программы.
Слайд 12

Область видимости переменных В данном случае число 3.14 представлено константой PI.

Область видимости переменных

В данном случае число 3.14 представлено константой PI. Понятно,

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

Модули Модуль в языке Python представляет отдельный файл с кодом, который

Модули

Модуль в языке Python представляет отдельный файл с кодом, который можно

повторно использовать в других программах.
Для создания модуля необходимо создать собственно файл с расширением *.py, который будет представлять модуль. Название файла будет представлять название модуля. Затем в этом файле надо определить одну или несколько функций.
Слайд 14

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

Модули

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

service.py, в той же папке, где находится hello.py.
Слайд 15

Модули Соответственно модуль будет называться service. И определим в нем следующий

Модули

Соответственно модуль будет называться service. И определим в нем следующий код:
Здесь определена

функция calculate_income, которая в качестве параметров получает процентную ставку вклада, сумму вклада и период, на который делается вклад, и высчитывает сумму, которая получится в конце данного периода.
Слайд 16

Модули В файле hello.py используем данный модуль: Для использования модуля его

Модули

В файле hello.py используем данный модуль:
Для использования модуля его надо импортировать с помощью

оператора import, после которого указывается имя модуля: import service.
Слайд 17

Модули Чтобы обращаться к функциональности модуля, нам нужно получить его пространство

Модули

Чтобы обращаться к функциональности модуля, нам нужно получить его пространство имен. По

умолчанию оно будет совпадать с именем модуля, то есть в нашем случае также будет называться service.
Получив пространство имен модуля, мы сможем обратиться к его функциям по схеме пространство_имен.функция:
service.calculate_income(rate, money, period)
Слайд 18

Модули И после этого мы можем запустить главный скрипт hello.py, и

Модули

И после этого мы можем запустить главный скрипт hello.py, и он

задействует модуль service.py. В частности, консольный вывод мог бы быть следующим:
Слайд 19

Модули Настройка пространства имен По умолчанию при импорте модуля он доступен

Модули

Настройка пространства имен
По умолчанию при импорте модуля он доступен через одноименное

пространство имен. Однако мы можем переопределить это поведение. Так, ключевое слово as позволяет сопоставить модуль с другим пространством имен. Например:
В данном случае пространство имен будет называться srv.
Слайд 20

Модули Другой вариант настройки предполагает импорт функциональности модуля в глобальное пространство

Модули

Другой вариант настройки предполагает импорт функциональности модуля в глобальное пространство имен

текущего модуля с помощью ключевого слова from:
В данном случае мы импортируем из модуля service в глобальное пространство имен функцию calculate_income. Поэтому мы сможем ее использовать без указания пространства имен модуля как если бы она была определена в этом же файле.
Слайд 21

Модули Если бы в модуле service было бы несколько функций, то

Модули

Если бы в модуле service было бы несколько функций, то могли

бы их импортировать в глобальное пространство имен одним выражением:
Но стоит отметить, что импорт в глобальное пространство имен чреват коллизиями имен функций. Например, если у нас том же файле определена функция с тем же именем, то при вызове функции мы можем получить ошибку. Поэтому лучше избегать использования импорта в глобальное пространство имен.
Слайд 22

Модули Имя модуля В примере выше модуль hello.py, который является главным,

Модули

Имя модуля
В примере выше модуль hello.py, который является главным, использует модуль

service.py. При запуске модуля hello.py программа выполнит всю необходимую работу. Однако, если мы запустим отдельно модуль service.py сам по себе, то ничего на консоли не увидим. Ведь модуль просто определяет функцию и не выполняет никаких других действий. Но мы можем сделать так, чтобы модуль service.py мог использоваться как сам по себе, так и подключаться в другие модули.
При выполнении модуля среда определяет его имя и присваивает его глобальной переменной __name__ (с обеих сторон два подчеркивания). Если модуль является запускаемым, то его имя равно __main__ (также по два подчеркивания с каждой стороны). Если модуль используется в другом модуле, то в момент выполнения его имя аналогично названию файла без расширения py. И мы можем это использовать.
Слайд 23

Модули Так, изменим содержимое файла service.py: Кроме того, для тестирования функции

Модули

Так, изменим содержимое файла service.py:
Кроме того, для тестирования функции определена главная функция main.

И мы можем сразу запустить файл service.py отдельно от всех и протестировать код.
Слайд 24

Модули Следует обратить внимание на вызов функции main: if __name__=="__main__": main()

Модули

Следует обратить внимание на вызов функции main:
if __name__=="__main__":
    main()
Переменная __name__ указывает на

имя модуля. Для главного модуля, который непосредственно запускается, эта переменная всегда будет иметь значение __main__ вне зависимости от имени файла.
Поэтому, если мы будем запускать скрипт service.py отдельно, сам по себе, то Python присвоит переменной __name__ значение __main__, далее в выражении if вызовет функцию main из этого же файла.
Однако если мы будем запускать другой скрипт, а этот - service.py - будем подключать в качестве вспомогательного, для service.py переменная __name__ будет иметь значение service. И соответственно метод main в файле service.py не будет работать.
Данный подход с проверкой имени модуля является более рекомендуемым подходом, чем просто вызов метода main.
Слайд 25

Модули В файле hello.py также можно сделать проверку на то, является

Модули

В файле hello.py также можно сделать проверку на то, является ли

модуль главным (хотя в принципе это необязательно):
Слайд 26

Обработка исключений При программировании на Python мы можем столкнуться с двумя

Обработка исключений

При программировании на Python мы можем столкнуться с двумя типами

ошибок. Первый тип представляют синтаксические ошибки (syntax error). Они появляются в результате нарушения синтаксиса языка программирования при написании исходного кода. При наличии таких ошибок программа не может быть скомпилирована. При работе в какой-либо среде разработки, например, в PyCharm, IDE сама может отслеживать синтаксические ошибки и каким-либо образом их выделять.
Слайд 27

Обработка исключений Второй тип ошибок представляют ошибки выполнения (runtime error). Они

Обработка исключений

Второй тип ошибок представляют ошибки выполнения (runtime error). Они появляются в уже

скомпилированной программе в процессе ее выполнения. Подобные ошибки еще называются исключениями. Например, в прошлых темах мы рассматривали преобразование числа в строку:
Данный скрипт успешно скомпилируется и выполнится, так как строка "5" вполне может быть конвертирована в число.
Слайд 28

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

Обработка исключений

Однако возьмем другой пример:
При выполнении этого скрипта будет выброшено исключение

ValueError, так как строку "hello" нельзя преобразовать в число.
Слайд 29

Обработка исключений С одной стороны, здесь очевидно, сто строка не представляет

Обработка исключений

С одной стороны, здесь очевидно, сто строка не представляет число,

но мы можем иметь дело с вводом пользователя, который также может ввести не совсем то, что мы ожидаем:
Слайд 30

Обработка исключений При возникновении исключения работа программы прерывается, и чтобы избежать

Обработка исключений

При возникновении исключения работа программы прерывается, и чтобы избежать подобного

поведения и обрабатывать исключения в Python есть конструкция try..except, которая имеет следующее формальное определение:
try:
    инструкции
except [Тип_исключения]:
    инструкции
Весь основной код, в котором потенциально может возникнуть исключение, помещается после ключевого слова try. Если в этом коде генерируется исключение, то работа кода в блоке try прерывается, и выполнение переходит в блок except.
После ключевого слова except опционально можно указать, какое исключение будет обрабатываться (например, ValueError или KeyError). После слова except на следующей стоке идут инструкции блока except, выполняемые при возникновении исключения.
Слайд 31

Обработка исключений Рассмотрим обработку исключения на примере преобразовании строки в число:

Обработка исключений

Рассмотрим обработку исключения на примере преобразовании строки в число:

Слайд 32

Обработка исключений В примере выше обрабатывались сразу все исключения, которые могут

Обработка исключений

В примере выше обрабатывались сразу все исключения, которые могут возникнуть

в коде. Однако мы можем конкретизировать тип обрабатываемого исключения, указав его после слова except:
Слайд 33

Обработка исключений Если ситуация такова, что в программе могут быть сгенерированы

Обработка исключений

Если ситуация такова, что в программе могут быть сгенерированы различные

типы исключений, то мы можем их обработать по отдельности, используя дополнительные выражения except:
Слайд 34

Обработка исключений Если возникнет исключение в результате преобразования строки в число,

Обработка исключений

Если возникнет исключение в результате преобразования строки в число, то

оно будет обработано блоком except ValueError. Если же второе число будет равно нулю, то есть будет деление на ноль, тогда возникнет исключение ZeroDivisionError, и оно будет обработано блоком except ZeroDivisionError.
Тип Exception представляет общее исключение, под которое попадают все исключительные ситуации. Поэтому в данном случае любое исключение, которое не представляет тип ValueError или ZeroDivisionError, будет обработано в блоке except Exception:.
Слайд 35

Обработка исключений Если возникнет исключение в результате преобразования строки в число,

Обработка исключений

Если возникнет исключение в результате преобразования строки в число, то

оно будет обработано блоком except ValueError. Если же второе число будет равно нулю, то есть будет деление на ноль, тогда возникнет исключение ZeroDivisionError, и оно будет обработано блоком except ZeroDivisionError.
Тип Exception представляет общее исключение, под которое попадают все исключительные ситуации. Поэтому в данном случае любое исключение, которое не представляет тип ValueError или ZeroDivisionError, будет обработано в блоке except Exception:.
Слайд 36

Обработка исключений Блок finally При обработке исключений также можно использовать необязательный

Обработка исключений

Блок finally
При обработке исключений также можно использовать необязательный блок finally. Отличительной

особенностью этого блока является то, что он выполняется вне зависимости, было ли сгенерировано исключение:
Как правило, блок finally применяется для освобождения используемых ресурсов, например, для закрытия файлов.
Слайд 37

Обработка исключений Получение информации об исключении С помощью оператора as мы

Обработка исключений

Получение информации об исключении
С помощью оператора as мы можем передать всю информацию

об исключении в переменную, которую затем можно использовать в блоке except:
Слайд 38

Обработка исключений Генерация исключений Иногда возникает необходимость вручную сгенерировать то или

Обработка исключений

Генерация исключений
Иногда возникает необходимость вручную сгенерировать то или иное исключение.

Для этого применяется оператор raise. При вызове исключения мы можем ему передать сообщение, которое затем можно вывести пользователю.
Слайд 39

Списки Для работы с наборами данных Python предоставляет такие встроенные типы

Списки

Для работы с наборами данных Python предоставляет такие встроенные типы как

списки, кортежи и словари.
Список (list) представляет тип данных, который хранит набор или последовательность элементов. Для создания списка в квадратных скобках ([]) через запятую перечисляются все его элементы. Во многих языках программирования есть аналогичная структура данных, которая называется массив. Например, определим список чисел:
Слайд 40

Списки Также для создания списка можно использовать конструктор list(): Оба этих

Списки

Также для создания списка можно использовать конструктор list():
Оба этих определения списка аналогичны

- они создают пустой список.
Конструктор list для создания списока может принимать другой список:
Слайд 41

Списки Для обращения к элементам списка надо использовать индексы, которые представляют

Списки

Для обращения к элементам списка надо использовать индексы, которые представляют номер

элемента в списка. Индексы начинаются с нуля. То есть второй элемент будет иметь индекс 1. Для обращения к элементам с конца можно использовать отрицательные индексы, начиная с -1. То есть у последнего элемента будет индекс -1, у предпоследнего - -2 и так далее.
Слайд 42

Списки Если необходимо создать список, в котором повторяется одно и то

Списки

Если необходимо создать список, в котором повторяется одно и то же

значение несколько раз, то можно использовать символ звездочки *. Например, определим список из шести пятерок:
Слайд 43

Списки Кроме того, если нам необходим последовательный список чисел, то для

Списки

Кроме того, если нам необходим последовательный список чисел, то для его

создания удобно использовать функцию range, которая имеет три формы:
range(end): создается набор чисел от 0 до числа end
range(start, end): создается набор чисел от числа start до числа end
range(start, end, step): создается набор чисел от числа start до числа end с шагом step
Слайд 44

Списки Список необязательно должен содержать только однотипные объекты. Мы можем поместить

Списки

Список необязательно должен содержать только однотипные объекты. Мы можем поместить в

один и тот же список одновременно строки, числа, объекты других типов данных:
Слайд 45

Списки Перебор элементов Для перебора элементов можно использовать как цикл for,

Списки

Перебор элементов
Для перебора элементов можно использовать как цикл for, так и

цикл while.
Перебор с помощью цикла for:
Здесь вместо функции range мы сразу можем подставить имеющийся список companies.
Слайд 46

Списки Перебор с помощью цикла while: Для перебора с помощью функции

Списки

Перебор с помощью цикла while:
Для перебора с помощью функции len() получаем длину списка.

С помощью счетчика i выводит по элементу, пока значение счетчика не станет равно длине списка.
Слайд 47

Списки Сравнение списков Два списка считаются равными, если они содержат один

Списки

Сравнение списков
Два списка считаются равными, если они содержат один и тот

же набор элементов:
В данном случае оба списка будут равны.
Слайд 48

Списки Методы и функции по работе со списками Для управления элементами

Списки

Методы и функции по работе со списками
Для управления элементами списки имеют

целый ряд методов. Некоторые из них:
append(item): добавляет элемент item в конец списка
insert(index, item): добавляет элемент item в список по индексу index
remove(item): удаляет элемент item. Удаляется только первое вхождение элемента. Если элемент не найден, генерирует исключение ValueError
clear(): удаление всех элементов из списка
index(item): возвращает индекс элемента item. Если элемент не найден, генерирует исключение ValueError
pop([index]): удаляет и возвращает элемент по индексу index. Если индекс не передан, то просто удаляет последний элемент.
count(item): возвращает количество вхождений элемента item в список
sort([key]): сортирует элементы. По умолчанию сортирует по возрастанию. Но с помощью параметра key мы можем передать функцию сортировки.
reverse(): расставляет все элементы в списке в обратном порядке
Слайд 49

Списки Кроме того, Python предоставляет ряд встроенных функций для работы со

Списки

Кроме того, Python предоставляет ряд встроенных функций для работы со списками:
len(list):

возвращает длину списка
sorted(list, [key]): возвращает отсортированный список
min(list): возвращает наименьший элемент списка
max(list): возвращает наибольший элемент списка
Слайд 50

Списки Добавление и удаление элементов Для добавления элемента применяются методы append()

Списки

Добавление и удаление элементов
Для добавления элемента применяются методы append() и insert, а для удаления

- методы remove(), pop() и clear().
Использование методов:
Слайд 51

Списки Проверка наличия элемента Если определенный элемент не найден, то методы

Списки

Проверка наличия элемента
Если определенный элемент не найден, то методы remove и

index генерируют исключение. Чтобы избежать подобной ситуации, перед операцией с элементом можно проверять его наличие с помощью ключевого слова in:
Выражение item in companies возвращает True, если элемент item имеется в списке companies. Поэтому конструкция if item in companies может выполнить последующий блок инструкций в зависимости от наличия элемента в списке.
Слайд 52

Списки Подсчет вхождений Если необходимо узнать, сколько раз в списке присутствует

Списки

Подсчет вхождений
Если необходимо узнать, сколько раз в списке присутствует тот или

иной элемент, то можно применить метод count():
Слайд 53

Списки Сортировка Для сортировки по возрастанию применяется метод sort(): Если необходимо

Списки

Сортировка
Для сортировки по возрастанию применяется метод sort():
Если необходимо отсортировать данные в обратном

порядке, то мы можем после сортировки применить метод reverse():
Слайд 54

Списки При сортировке фактически сравниваются два объекта, и который из них

Списки

При сортировке фактически сравниваются два объекта, и который из них "меньше",

ставится перед тем, который "больше". Понятия "больше" и "меньше" довольно условны. И если для чисел все просто - числа расставляются в порядке возрастания, то для строк и других объектов ситуация сложнее. В частности, строки оцениваются по первым символам. Если первые символы равны, оцениваются вторые символы и так далее. При чем цифровой символ считается "меньше", чем алфавитный заглавный символ, а заглавный символ считается меньше, чем строчный.
Слайд 55

Списки Таким образом, если в списке сочетаются строки с верхним и

Списки

Таким образом, если в списке сочетаются строки с верхним и нижним

регистром, то мы можем получить не совсем корректные результаты, так как для нас строка "bob" должна стоять до строки "Tom". И чтобы изменить стандартное поведение сортировки, мы можем передать в метод sort() в качестве параметра функцию:
Слайд 56

Списки Кроме метода sort мы можем использовать встроенную функцию sorted, которая

Списки

Кроме метода sort мы можем использовать встроенную функцию sorted, которая имеет две

формы:
sorted(list): сортирует список list
sorted(list, key): сортирует список list, применяя к элементам функцию key
При использовании этой функции следует учитывать, что эта функция не изменяет сортируемый список, а все отсортированные элементы она помещает в новый список, который возвращается в качестве результата.
Слайд 57

Списки Минимальное и максимальное значения Встроенный функции Python min() и max()

Списки

Минимальное и максимальное значения
Встроенный функции Python min() и max() позволяют найти минимальное и максимальное значения

соответственно:
Слайд 58

Списки Копирование списков При копировании списков следует учитывать, что списки представляют

Списки

Копирование списков
При копировании списков следует учитывать, что списки представляют изменяемый (mutable)

тип, поэтому если обе переменных будут указывать на один и тот же список, то изменение одной переменной, затронет и другую переменную:
Слайд 59

Списки Это так называемое "поверхностное копирование" (shallow copy). И, как правило,

Списки

Это так называемое "поверхностное копирование" (shallow copy). И, как правило, такое

поведение нежелательное. И чтобы происходило копирование элементов, но при этом переменные указывали на разные списки, необходимо выполнить глубокое копирование (deep copy). Для этого можно использовать метод deepcopy(), который определен во встроенном модуле copy:
Слайд 60

Списки Копирование части списка Если необходимо скопировать не весь список, а

Списки

Копирование части списка
Если необходимо скопировать не весь список, а только его

какую-то определенную часть, то мы можем применять специальный синтаксис. который может принимать следующие формы:
list[:end]: через параметр end передается индекс элемента, до которого нужно копировать список
list[start:end]: параметр start указывает на индекс элемента, начиная с которого надо скопировать элементы
list[start:end:step]: параметр step указывает на шаг, через который будут копироваться элементы из списка. По умолчанию этот параметр равен 1.
Слайд 61

Списки Копирование части списка

Списки

Копирование части списка

Слайд 62

Списки Соединение списков Для объединения списков применяется операция сложения (+):

Списки

Соединение списков
Для объединения списков применяется операция сложения (+):

Слайд 63

Списки Списки списков Списки кроме стандартных данных типа строк, чисел, также

Списки

Списки списков
Списки кроме стандартных данных типа строк, чисел, также могут содержать

другие списки. Подобные списки можно ассоциировать с таблицами, где вложенные списки выполняют роль строк. Например:
Слайд 64

Списки Чтобы обратиться к элементу вложенного списка, необходимо использовать пару индексов:

Списки

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

ко второму элементу первого вложенного списка.
Добавление, удаление и исменение общего списка, а также вложенных списков аналогично тому, как это делается с обычными (одномерными) списками:
Слайд 65

Списки Перебор вложенных списков:

Списки

Перебор вложенных списков:

Слайд 66

Кортежи Кортеж (tuple) представляет последовательность элементов, которая во многом похожа на

Кортежи

Кортеж (tuple) представляет последовательность элементов, которая во многом похожа на список

за тем исключением, что кортеж является неизменяемым (immutable) типом. Поэтому мы не можем добавлять или удалять элементы в кортеже, изменять его.
Для создания кортежа используются круглые скобки, в которые помещаются его значения, разделенные запятыми:
Слайд 67

Кортежи Также для определения кортежа мы можем просто перечислить значения через

Кортежи

Также для определения кортежа мы можем просто перечислить значения через запятую

без применения скобок:
Если вдруг кортеж состоит из одного элемента, то после единственного элемента кортежа необходимо поставить запятую:
Слайд 68

Кортежи Для создания кортежа из списка можно передать список в функцию tuple(), которая возвратит кортеж:

Кортежи

Для создания кортежа из списка можно передать список в функцию tuple(), которая

возвратит кортеж:
Слайд 69

Кортежи Обращение к элементам в кортеже происходит также, как и в

Кортежи

Обращение к элементам в кортеже происходит также, как и в списке

по индексу. Индексация начинается также с нуля при получении элементов с начала списка и с -1 при получении элементов с конца списка:
Слайд 70

Кортежи Но так как кортеж - неизменяемый тип (immutable), то мы

Кортежи

Но так как кортеж - неизменяемый тип (immutable), то мы не

сможем изменить его элементы. То есть следующая запись работать не будет:
Слайд 71

Кортежи При необходимости мы можем разложить кортеж на отдельные переменные:

Кортежи

При необходимости мы можем разложить кортеж на отдельные переменные:

Слайд 72

Кортежи Особенно удобно использовать кортежи, когда необходимо возвратить из функции сразу

Кортежи

Особенно удобно использовать кортежи, когда необходимо возвратить из функции сразу несколько

значений. Когда функция возвращает несколько значений, фактически она возвращает в кортеж:
Слайд 73

Кортежи С помощью встроенной функции len() можно получить длину кортежа:

Кортежи

С помощью встроенной функции len() можно получить длину кортежа:

Слайд 74

Кортежи Перебор кортежей Для перебора кортежа можно использовать стандартные циклы for

Кортежи

Перебор кортежей
Для перебора кортежа можно использовать стандартные циклы for и while. С помощью цикла

for:
С помощью цикла while:
Слайд 75

Кортежи Как для списка с помощью выражения элемент in кортеж можно проверить наличие элемента в кортеже:

Кортежи

Как для списка с помощью выражения элемент in кортеж можно проверить наличие элемента

в кортеже:
Слайд 76

Кортежи Сложные кортежи Один кортеж может содержать другие кортежи в виде элементов. Например:

Кортежи

Сложные кортежи
Один кортеж может содержать другие кортежи в виде элементов. Например: