№36 Namedtuple (именные кортежи) / для начинающих

Предыдущий урок: Инструкция assert

Именованные кортежи (namedtuple) — это подкласс кортежей в Python. У них те же функции, что и у обычных, но их значения можно получать как с помощью имени (через точку, например, .name), так и с помощью индекса (например [0]). В этом материале на примерах разберем синтаксис и функции этих кортежей.

Зачем нужны именованные кортежи?

Именованные кортежи улучшают читаемость кода и отдельных функций.

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


marks = (98, 80, 95)
print(marks)
print(marks[0])
print(marks[2])
(98, 80, 95)
98
95

Namedtuple — это замена обычных кортежей. Они выполняют те же функции, но улучшают читаемость кода. Даже если программист приостановит работу над программой на несколько месяцев, синтаксис или значение самого кортежа будут говорить сами за себя. Теперь время поговорить о самом синтаксисе таких кортежей.

Импорт именованных кортежей в Python

По сравнению с другими структурами данных в Python (список, словарь, кортеж и множество) именованный кортеж — не часть стандартной библиотеки. Он доступен в модуле collections. Последний включает и другие альтернативы встроенных структур в Python.

Когда namedtuple импортирован, можно переходить к его использованию.

Синтаксис namedtuple в Python

collections.namedtuple(typename, field_names, *, 
                       rename=False, defaults=None, module=None)

Создание именованного кортежа

Мы уже импортировали именованный кортеж, теперь рассмотрим синтаксис.


from collections import namedtuple

Marks = namedtuple('Marks', 'Physics Chemistry Math English')
marks = Marks(90, 85, 95, 100)
print(marks)
Marks(Physics=90, Chemistry=85, Math=95, English=100)

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

В качестве второго параметра можно использовать итерируемую структуру данных: список, словарь, кортеж или множество.
Если же это строка, то разные имена нужно разделить с помощью отдельного символа.

marks = Marks(90, 85, 95, 100) — эта строка создает именованный кортеж. «Marks» — это объявление именованного кортежа, которое может использоваться для создания бесконечного количества аналогичных структур. Это еще называется фабрикой именованных кортежей.

Позиционные аргументы соответствуют определению кортежа.
Для улучшения читабельности можно создавать именованные кортежи с помощью ключевых слов: marks = Marks(Physics=90, Chemistry=85, Math=95, English=100).

Создание namedtuple с помощью списка


from collections import namedtuple

lst = ['Physics', 'Chemistry', 'Math', 'English']
Marks = namedtuple('Marks', lst)
marks = Marks(90, 85, 95, 100)
print(marks)

Создание namedtuple с помощью словаря

Стартовое значение словаря — 0, поскольку значение поля игнорируется кортежем.


from collections import namedtuple

dct = {'Physics': 0, 'Chemistry': 0, 'Math': 0, 'English': 0}
Marks = namedtuple('Marks', dct)
marks = Marks(90, 85, 95, 100)
print(marks)

Создание namedtuple с помощью кортежа


from collections import namedtuple

tupl = ('Physics', 'Chemistry', 'Math', 'English')
Marks = namedtuple('Marks', tupl)
marks = Marks(90, 85, 95, 100)
print(marks)

Создание namedtuple с помощью множества


from collections import namedtuple

subject_set = {'Physics', 'Chemistry', 'Math', 'English'}
Marks = namedtuple('Marks', subject_set)
marks = Marks(90, 85, 95, 100)
print(marks)

Вывод во всех примерах будет одинаковый:

Marks(Physics=90, Chemistry=85, Math=95, English=100)

Именованный кортеж можно создать с помощью любой структуры данных, поддерживающей итерацию.

Создание namedtuple с помощью функции _make

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


from collections import namedtuple

lst = ['Physics', 'Chemistry', 'Math', 'English']
Marks = namedtuple('Marks', lst)
marks = Marks._make([55, 78, 98, 90])
print(marks)
Marks(Physics=55, Chemistry=78, Math=98, English=90)

Функция _make также принимает итерируемый объект (в случае со словарем — значение).


marks = Marks._make({55: 'Physics', 78: 'Chemistry', 98: 'Math', 90: 'English'})
print(marks)

Доступ к именам полей namedtuple в python

Дальше рассмотрим, как получать доступ к полям в именованном кортеже. Для этого есть несколько способов:

  1. Через смещение.
  2. Через точку.
  3. getattr().

Доступ к полям можно получить тем же способом, что и в кортежах — с помощью индекса.

Также можно использовать названия полей по аналогии с атрибутами экземпляра класса.

Наконец, поля можно получить и с помощью функции getattr().

Именованные кортежи неизменяемые

Как и стандартные кортежи в Python именованные является неизменяемыми. Это значит, что после объявления значения кортежа не могут быть изменены.


>>> marks.Physics = 99

File ".\main.py", line 6, in
marks.Physics = 99
AttributeError: can't set attribute

Изменение значения поля namedtuple

Несмотря на неизменяемость есть способ, с помощью которого можно менять значение поля. Для этого используется функция _replace.


marks = marks._replace(Physics=99)
print(marks)
Marks(Physics=99, Chemistry=78, Math=98, English=90)

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

Далее: Функция __main__