Кортежи

Кортежи (tuples) очень похожи на списки, но являются неизменяемыми. Как мы видели, использование изменяемых объектов может приводить к неприятным сюрпризам.

Кортежи пишутся в круглых скобках. Если элементов $>1$ или 0, это не вызывает проблем. Но как записать кортеж с одним элементом? Конструкция (x) абсолютно легальна в любом месте любого выражения, и означает просто x. Чтобы избежать неоднозначности, кортеж с одним элементом x записывается в виде (x,).

In [1]:
(1,2,3)
Out[1]:
(1, 2, 3)
In [2]:
()
Out[2]:
()
In [3]:
(1,)
Out[3]:
(1,)

Скобки ставить не обязательно, если кортеж - единственная вещь в правой части присваивания.

In [4]:
t=1,2,3
t
Out[4]:
(1, 2, 3)

Работать с кортежами можно так же, как со списками. Нельзя только изменять их.

In [5]:
len(t)
Out[5]:
3
In [6]:
t[1]
Out[6]:
2
In [7]:
u=4,5
t+u
Out[7]:
(1, 2, 3, 4, 5)
In [8]:
2*u
Out[8]:
(4, 5, 4, 5)

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

In [9]:
x,y=1,2
In [10]:
x
Out[10]:
1
In [11]:
y
Out[11]:
2

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

In [12]:
x,y=y,x
In [13]:
x
Out[13]:
2
In [14]:
y
Out[14]:
1

Это проще, чем в других языках, где приходится использовать третью переменную.

В стандартной библиотеке есть полезный тип namedtuple:

In [15]:
from collections import namedtuple
point=namedtuple('point',('x','y','z'))
p=point(0,1,2)
print(p)
point(x=0, y=1, z=2)

К его полям можно обращаться как по имени, так и по номеру (как для обычного кортежа).

In [16]:
p.y,p[1]
Out[16]:
(1, 1)

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

In [17]:
p=point(y=1,z=2,x=0)
p
Out[17]:
point(x=0, y=1, z=2)

В этих объектах нет накладных расходов по памяти: только значения полей (как в structure в C или record в Pascal). Соответствие между именами полей и их номерами хранится в памяти один раз для всего типа (в нашем примере point). В этом состоит важное отличие от словарей с ключами-строками. Кроме того, невозможно длбавлять или удалять поля налету.