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

Именованные кортежи (NamedTuples) — это отличный способ сделать ваш код на Python более полезным и читаемым. Если говорить коротко, именованный кортеж — это альтернатива встроенному кортежу. От стандартного кортежа именованный отличается тем, что к его элементам можно обращаться как по имени атрибута, так и по позиционному индексу, подобно тому, как это делается в Pandas DataFrame.

От редакции Pythonist: о датафреймах Pandas читайте в статье «Как создать Pandas DataFrame».

Примечание автора: код для этого руководства доступен по ссылке: https://github.com/StatsGary/PyHacks-Tutorials/blob/main/27_namedtuples.py.

Создание списка кортежей для сравнения

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

rockers_list = [
    ('Dave Grohl', ' Foo Fighters'),
    ('Jimmy Page', 'Led Zeppelin'),
    ('Robert Plant', 'Led Zeppelin'),
    ('Roger Daltrey', 'The Who'),
    ('James Hetfield', 'Metallica'),
    ('Dave Mustaine', 'Megadeth'),
    ('Eddie Vedder', 'Pearl Jam'),
    ('Ronnie James Dio', 'Dio'),
    ('Howard Jones', 'Killswitch Engage')
]

Затем создадим стандартный цикл для вывода результатов:

for rocker in rockers_list:
    print('The rockers name is {}'.format(rocker[0]))

Единственный способ получить имя рокера из такого списка кортежей — использовать позиционный индекс. В примере мы берем индекс 0, чтобы получить первый элемент кортежа (имя), а название группы будет под индексом 1. Это ограничение стандартных кортежей.

Вывод:

The rockers name is Dave Grohl
The rockers name is Jimmy Page
The rockers name is Robert Plant
The rockers name is Roger Daltrey
The rockers name is James Hetfield
The rockers name is Dave Mustaine
The rockers name is Eddie Vedder
The rockers name is Ronnie James Dio
The rockers name is Howard Jones

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

Приступаем к использованию namedtuple. Во-первых, нам нужно импортировать его из пакета collections:

from collections import namedtuple

Реализация namedtuple

Для начала нам нужно реализовать структуру именованного кортежа:

Rockers = namedtuple('Rockers', ['rocker_name', 'band'])

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

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

Далее я создам список, как в первом примере, но на этот раз внутренние кортежи я создам с именем переменной, которое я определил. В данном случае это будет Rockers, поскольку именно так я назвал свою переменную для namedtuple, но у вас может быть любое другое имя. Реализация:

rocker_named_tuple_list = [
    Rockers('Dave Grohl', ' Foo Fighters'),
    Rockers('Jimmy Page', 'Led Zeppelin'),
    Rockers('Robert Plant', 'Led Zeppelin'),
    Rockers('Roger Daltrey', 'The Who'),
    Rockers('James Hetfield', 'Metallica'),
    Rockers('Dave Mustaine', 'Megadeth'),
    Rockers('Eddie Vedder', 'Pearl Jam'),
    Rockers('Ronnie James Dio', 'Dio'),
    Rockers('Howard Jones', 'Killswitch Engage')
]

Как видите, реализация соответствует определенной нами структуре namedtuple.

Перебор списка в цикле и обращение к элементам по имени

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

for rocker in rocker_named_tuple_list:
    print(f'Rocker is: {rocker.rocker_name} and band is: {rocker.band}')

Результат:

Rocker is: Dave Grohl and band is:  Foo Fighters
Rocker is: Jimmy Page and band is: Led Zeppelin
Rocker is: Robert Plant and band is: Led Zeppelin
Rocker is: Roger Daltrey and band is: The Who
Rocker is: James Hetfield and band is: Metallica
Rocker is: Dave Mustaine and band is: Megadeth
Rocker is: Eddie Vedder and band is: Pearl Jam
Rocker is: Ronnie James Dio and band is: Dio
Rocker is: Howard Jones and band is: Killswitch Engage

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

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

Я возьму Dave Grohl по индексу 0, а затем заменю один из элементов кортежа, band, с Foo Fighters на Nirvana:

replace_example = rocker_named_tuple_list[0] # Get Dave Grohl and add his band to Nirvana
replace_example = replace_example._replace(band='Nirvana')
print(replace_example)

Вывод показывает, что это значение было изменено:

Rockers(rocker_name='Dave Grohl', band='Nirvana')

Другие возможности именованных кортежей

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

Преобразование списка в именованный кортеж

Допустим, у вас есть список с той же структурой. Вы можете довольно просто конвертировать его в именованный кортеж:

# Автоматическое преобразование списка в именованный кортеж
rocker_list_make = ['Kurt Cobain', 'Nirvana']
rocker_made_from_list = Rockers._make(rocker_list_make)
print(rocker_made_from_list)

Как видите, при помощи команды ._make мы превратили список в именованный кортеж:

Rockers(rocker_name='Kurt Cobain', band='Nirvana')

Вуаля!

Преобразование словаря в именованный кортеж

Процесс очень похож на описанный выше, но теперь у нас будет не список, а словарь. Вот как делается преобразование:

# Преобразование словаря в именованный кортеж
my_rocker_dict = {'rocker_name': 'Zack De La Rocha', 'band':'Rage Against The Machine'}
make_dict_named_tuple = Rockers(**my_rocker_dict)
print(make_dict_named_tuple)

Мы использовали оператор распаковки для передачи нескольких kwargs из словаря в именованный кортеж. Эти kwargs становятся атрибутами и значениями именованного кортежа. В выводе мы получаем следующий результат:

Rockers(rocker_name='Zack De La Rocha', band='Rage Against The Machine')

От редакции Pythonist: о том, что такое kwargs, читайте в статье «Python *args and **kwargs».

Итоги

Мы разобрали, что собой представляют именованные кортежи в Python, чем они отличаются от обычных и как их создавать. Также мы на примерах рассмотрели преобразование списков и словарей в именованные кортежи.

Перевод статьи «Narly NamedTuples in Python».