Кортежи (tuple) в Python

Возможно, вы уже знакомы со списками в Python. Это набор данных, который может хранить переменные, числа, строки и другие значения. Кортеж – это очень похожая структура данных, которая может содержать элементы разных типов, которые перечисляются через запятую. Но у них есть одно отличие по сравнению со списками. Какое? Давайте разберемся подробнее. 

Для начала необходимо разобраться, какие вообще операции можно совершать со списками. Это чтение и запись. Можно как прочитать элемент, так и изменить его содержимое. А если нужно, и вовсе можно его удалить. Основное отличие кортежа от списка в том, что возможно исключительно чтение. Кортеж создается один раз, после чего уже больше никогда не может быть изменен.

В то время, как список заключается в квадратные скобки, кортеж – в круглые. 

Чтобы создать его, необходимо написать название переменной, которой будет присваиваться соответствующий элемент, потом написать оператор присваивания (который являет собой знак «равно» (=)), перечислить элементы и закрыть скобку.

Вот пример кода, который демонстрирует работу кортежа. 

thistuple = ("помидор",  "огурец",  "лук")

print(thistuple)

Если запустить этот код, в строке консоли появится последовательность (‘помидор’, ‘огурец’, ‘лук’), что идентично содержимому кортежа. 

Работа с отдельными элементами кортежа

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

Принцип такой же самый, как и в списках. Сначала идет элемент с нулевым индексом, потом с первым – и так далее. 

Например, если нам надо вывести второй элемент по счету, необходимо указать в качестве аргумента функции print() название кортежа и указать индекс 1 в квадратных скобках.

Вот пример фрагмента кода, демонстрирующего это. 

thistuple = ("помидор",  "огурец",  "лук")

print(thistuple[1])

Задание: какой элемент будет выведен интерпретатором после того, как запустить этот фрагмент кода? Попробуйте сначала назвать правильный ответ, не запуская эти строки у себя, а также – не подсматривая эти данные ниже.

Правильный ответ – огурец. Причина проста – этот элемент имеет индекс 1.

Изменение элемента кортежа

Начинающие разработчики нередко интересуются возможностью редактировать кортеж. Но, к сожалению, это сделать не получится, поскольку в кортеж невозможно вносить какие-то изменения. Если необходимо сделать редактируемую последовательность элементов, то тогда нужно использовать списки. 

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

thistuple = ("помидор",  "огурец",  "лук")

thistuple[1] =  "морковка" 




Traceback (most recent call last):

  File "<pyshell#3>", line 1, in <module>

    thistuple[1] =  "морковка"

TypeError: 'tuple' object does not support item assignment

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

Здесь у читателя может появиться вопрос: зачем отдельный объект, который нельзя изменять? Ведь можно просто создать список и не вносить в него никаких коррективов. К слову, кортежи легко преобразовываются в списки и наоборот, используя функции 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)

К слову, этот фрагмент кода демонстрирует, как не надо писать код в Python. Хотя учитывая то, что ошибок не будет никаких выдано, это не так понятно, как в случае с другими неправильными фрагментами кода приложений. 

Почему неправильно? Посмотрите на вывод, который будет осуществлен интерпретатором после того, как запустить этот код.  

[6, 9, 5, 9]

[6, 9, 5, 9]

Проще говоря, исходный список также был отредактирован. Параметр seq ссылался на не на список-оригинал, а на собственный список. Поэтому нет никакой необходимости в использовании оператора return

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

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)

В результате исполнения этого кода будет на вывод запущена такая последовательность значений. 

[3, 6, 2, 6]

[6, 9, 5, 9]

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

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

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

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

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

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])

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

Поэтому, используя список внутри кортежа, можно осуществлять точечные изменения.  

>>> 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])

Итерация по кортежу

Пользователь может перебирать элементы кортежа с помощью цикла for точно так же, как и с любым другим итерируемым объектом. Если использовать этот фрагмент кода, то тогда вывод будет таким. 

помидор

огурец

лук

Сам код такой: 

thistuple = ("помидор",  "огурец",  "лук")

for x in thistuple:  

    print(x)

Принцип использования цикла for с кортежами такой же самый, как и с другими итерируемыми объектами.

Как узнать величину кортежа?

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

thistuple = ("помидор",  "огурец",  "лук")

print(len(thistuple))

Выведется число 3, поскольку в состав кортежа входит три элемента.

Добавление и удаление элементов

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

Будет выдана следующая ошибка. 

Traceback (most recent call last):

  File "<pyshell#3>", line 1, in <module>

    thistuple[3] =  "морковка"

TypeError: 'tuple' object does not support item assignment

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

thistuple = ("помидор",  "огурец",  "лук")  

del thistuple  

print(thistuple)  # эта команда вызовет ошибку, так как thistuple больше не существует

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

ОфисГуру
Adblock
detector