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

>>> a = (10, 2.13, 
    "square", 89, "C")
>>> a
(10, 2.13, 'square', 89, 'C')

Кортеж позволяет извлекать элементы и осуществлять срезы:

>>> a[3]
89
>>> a[1:3]
(2.13, 'square')

Но изменение элементов невозможно:

>>> a[0] = 11
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Тип tuple лишен методов для модификации состава элементов.

Зачем же использовать кортежи, если они только имитируют списки без возможности их редактирования? Ответ прост: кортежи позволяют защитить данные от изменений. Если понадобится преобразовать кортеж в список и обратно, то в Python предусмотрены функции list() и tuple():

>>> a = (10, 2.13, 
    "square", 89, "C")
>>> b = [1, 2, 3]
>>> c = list(a)
>>> d = tuple(b)
>>> c
[10, 2.13, 'square', 89, 'C']
>>> d
(1, 2, 3)

Теперь о том, где кортежи могут быть особенно полезны: при передаче изменяемых объектов в функцию в Python используется механизм передачи по ссылке. Это подразумевает, что не происходит создание копии объекта, а передается ссылка на существующий объект. Если объект в функции изменяется, это затрагивает и исходный объект в глобальной области.

def addNum(seq, num):
    for i in range(len(seq)):
        seq[i] += num
    return seq

origin = [3, 6, 2, 6]
changed = addNum(origin, 3)

print(origin)
print(changed)

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

def addNum(seq, num):
    for i in range(len(seq)):
        seq[i] += num

origin = [3, 6, 2, 6]
addNum(origin, 3)
print(origin)

Как поступить, если необходим новый список на основе имеющегося, но без изменений оригинала? Можно создать копию внутри функции и возвратить её:

def addNum(seq, num):
    new_seq = []
    for i in seq:
        new_seq.append(i + num)
    return new_seq

origin = [3, 6, 2, 6]
changed = addNum(origin, 3)

print(origin)
print(changed)

Таким образом, оригинал остается без изменений, а элементы лишь добавляются в новую структуру.

Ещё один подход - использование кортежей, ведь в больших приложениях проверить, что ни одна функция не меняет глобальные данные, непросто.

Лучше с самого начала сделать глобальный список кортежем. Ведь неизменяемые объекты передаются по значению, и передаваемая в функцию структура - это именно копия. Даже если вы случайно передадите оригинал, изменить его содержимое невозможно. Для манипуляций понадобится создать копию или изменить тип, создав новую локальную структуру.

def addNum(seq, num):
    seq = list(seq)
    for i in range(len(seq)):
        seq[i] += num
    return seq

origin = (3, 6, 2, 6)
changed = addNum(origin, 3)

print(origin)
print(changed)

Списки в кортежах

Кортежи могут содержать списки, подобно тому как списки могут содержать другие списки.

>>> nested = (1, "do", 
    ["param", 10, 20])

Можем ли мы изменить список ["param", 10, 20], который встроен в кортеж nested? Отвечаем утвердительно. Хотя сам кортеж неизменяем, вложенный список изменяем.

>>> nested[2][1] = 15
>>> nested
(1, 'do', ['param', 15, 20])

Индексация вида nested[2][1] помогает получать доступ к вложенным объектам: первый индекс указывает на позицию внутри кортежа, второй - на конкретный элемент внутри объекта. Так список внутри кортежа имеет индекс 2, а число 10 в списке - индекс 1.

Выражение довольно странное: кортеж неприступен для изменений, однако можно изменять то, что в него вложено. На деле, мы не меняем сам кортеж, а его ссылку на объект.

Для наглядности изменим пример:

>>> l = ["param", 10, 20]
>>> t = (1, "do", l)
>>> t
(1, 'do', ['param', 10, 20])

Кортеж содержит ссылку на список. Сама ссылка неизменна, но изменять содержимое списка можно:

>>> l.pop(0)
'param'
>>> t
(1, 'do', [10, 20])

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

>>> a = "Kat"
>>> t = (a, l)
>>> t
('Kat', [10, 20])
>>> a = "Bat"
>>> t
('Kat', [10, 20])

Неизменяемые типы передаются в кортеж аналогично параметрам в функцию – по значению. Это значит, что их значения копируются.

Практическая работа

  1. Чтобы избежать изменений в оригинальном списке, можно не прибегать к кортежу. Копия создается через метод copy() или срезом [:]. Проделайте копирование и убедитесь, что изменения не касаются оригинала.
  2. Создайте кортеж с десятью случайными числами от 0 до 5 включительно. На заполнение второго кортежа используйте числа от -5 до 0. Придумайте функцию для этой задачи. Объедините кортежи с помощью +, формируя третий. Применяя метод count(), найдите количество нулей в третьем кортеже и выведите его вместе с количеством нулей.

Вопросы для самопроверки:

  1. Чем кортежи (tuple) в Python принципиально отличаются от списков?
  2. Какие встроенные функции Python можно использовать для превращения кортежа в список и наоборот?
  3. Почему использование кортежей может быть более безопасным вариантом в больших программах?
  4. В каком случае возможно изменить содержимое объекта, находящегося в кортеже?

Программа курса:

  1. Описание курса
  2. Эволюция и основы языков программирования

    История программирования в кратком и понятном изложении. Что такое машинный язык, почему появились ассемблеры, языки высокого уровня и объектно-ориентированные. Зачем нужен транслятор, и почему он может быть либо компилятором, либо интерпретатором.

  3. Знакомство с основами Python

    Особенности языка Python, работа в интерактивном режиме и подготовка файлов с исходным кодом.

  4. Типы данных и переменные в Python

    Базовые типы данных в Python: целое, вещественное числа, строки. Изменение типа данных с помощью встроенных функций. Понятие об операциях и переменных. Присваивание значения переменной.

  5. Ввод и вывод данных с Python функциями

    Для вывода на экран в Python 3.x используется функция print(). Вывод может быть предварительно отформатирован. Для ввода данных с клавиатуры используется функция input(), которая возвращает в программу строку.

  6. Логические выражения и операторы в Python

    Логические выражения. Логические операторы языка Python: == (равно), != (не равно), (больше), = (больше или равно), and (логическое И), or (логическое ИЛИ), not (отрицание).

  7. Ветвление и условные операторы в Python

    Управление потоком программы с помощью операторов if-else. Создание логических ветвлений, обработка условий и выполнение разных блоков кода в Python.

  8. Изучите обработку ошибок и исключений в Python

    Общее представление об ошибках и исключениях в языке программирования Python. SyntaxError, NameError, TypeError, ValueError, ZeroDivisionError. Обработка исключений с помощью инструкции try-except.

  9. Множественное ветвление с if-elif-else в Python

    Оператор множественного ветвления языка Python позволяет организовать более двух веток выполнения программы без необходимости вложения условных операторов друг в друга. Конструкция включает одну ветку if, произвольное количество elif и необязательную ветку else.

  10. Цикл while и его применение в Python

    С помощью циклов в программировании организуется многократное следующее друг за другом выполнение одних и тех же участков кода. Бывают циклы с условием и со счетчиком. К первым относится цикл while, или цикл "пока".

  11. Изучите функции и их применение в Python

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

  12. Локальные и глобальные переменные в Python

    В программировании важное значение имеет представление о локальных и глобальных переменных. Локальные переменные существуют внутри функций и не доступны за ее пределами. Глобальные переменные видны во всей программе.

  13. Оператор return и возврат значений в Python

    С помощью оператора return можно вернуть значение из тела функции в основную программу. В языке программирования Python можно вернуть несколько значений, перечислив их через запятую после оператора return. Также в функции может быть несколько return, но всегда выполняется только один из них.

  14. Параметры и аргументы функций в Python

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

  15. Встроенные функции Python для работы

    Язык программирования Python включает множество встроенных функций. В предыдущих уроках мы использовали такие функции как print() и input(), а также функции преобразования типов данных. В этом уроке рассматриваются встроенные функции для работы с символами и числами.

  16. Использование модулей в Python

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

  17. Генерация псевдослучайных чисел в Python

    Для генерации псевдослучайных чисел в языке программирования Python используются функции модуля random. Функция random() генерирует вещественное число от 0 до 1. Функции randint() и randrange() производят целые псевдослучайные числа в указанных диапазонах.

  18. Изучение списков в Python - основы и операции

    Списки в Python - это аналог массивов в других языках программирования. Однако список может содержать элементы разных типов. В терминологии Python список - это изменяемая упорядоченная структура данных. Можно заменять его элементы, добавлять и удалять их, брать срезы. В язык встроены методы для работы со списками.

  19. Изучение цикла for в Python

    Цикл for в языке программирования Python предназначен для перебора элементов структур данных (списков, словарей, кортежей, множеств) и многих других объектов. Это не цикл со счетчиком, каковым является for во многих других языках. Нередко цикл for используется совместно с функцией range(), генерирующей объекты-диапазоны.

  20. Строки в Python - методы и срезы

    В Python строки - это неизменяемые последовательности символов или подстрок. Из них, так же как из списков, можно извлекать отдельные символы с помощью индексов или подстроки с помощью взятия срезов. В языке Python есть множество встроенных строковых методов, позволяющих упростить обработку строк.

  21. Кортежи - неизменяемые структуры данных

    Кортежи в Python - это неизменяемые структуры данных, состоящие из элементов одного или разных типов. Кортежи подобны спискам и обычно используются для защиты последних от изменений. Преобразование одного в другой выполняется с помощью встроенных функций tuple() и list().

  22. Словари в Python - работа с ключами и значениями

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

  23. Работа с файлами в Python

    В языке программирования Python открытие файлов выполняется с помощью функции open(), которой передается два аргумента - имя файла и режим. Файл может быть открыт в режиме чтения, записи, добавления. Также может быть указан тип файла - текстовый или бинарный. Для файлов есть ряд встроенных методов чтения, записи и др.