Шаг 74.
Python: тонкости программирования. Классы и ООП. Чем полезны именованные кортежи. Именованные кортежи спешат на помощь

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

    Именованные кортежи призваны решать эти две проблемы.

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

    Помимо этого, контейнеры типа namedtuple являются, скажем так, именованными кортежами (named tuples). Доступ к каждому хранящемуся в них объекту можно получить через уникальный (человекочитаемый) идентификатор. Это свойство освобождает вас от необходимости запоминать целочисленные индексы или обращаться к искусственным приемам, таким как определение целочисленных констант в качестве мнемокодов ваших индексов.

    Вот пример того, как выглядит именованный кортеж:

>>> from collections import namedtuple
>>> Car = namedtuple('Авто' , 'цвет пробег')

    Именованные кортежи были добавлены в стандартную библиотеку Python версии 2.6. Чтобы ими воспользоваться, необходимо импортировать модуль collections. В приведенном выше примере определен простой тип данных Car с двумя полями: цвет и пробег.

    Вам, возможно, любопытно, почему этом примере передается фабричной функции namedtuple() строковое значение 'Авто' в качестве первого аргумента.

    В документации Python этот параметр упоминается как "имя типа". Он является именем нового класса, который создается в результате вызова функции namedtuple().

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

    Имя класса используется в строке документации docstring и в реализации метода __repr__, которые функция namedtuple() генерирует для нас автоматически.

    В этом примере есть и другая синтаксическая диковинка - почему мы передаем поля в виде строки, в которой их имена закодированы как 'цвет пробег'?

    Ответ заключается в том, что фабричная функция namedtuple() вызывает функцию split() со строковым значением, содержащим имена полей, которая преобразовывает его в список имен полей. Так что в действительности это просто сокращенная запись для приведенных ниже двух шагов:

>>> 'цвет npo6er'.split()
['цвет', 'пробег']
>>> Car = namedtuple('Авто', ['цвет', 'пробег'])

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

>>> Car = namedtuple('Авто', [
     'цвет',
     'пробег',
])

    Что бы вы ни решили, теперь при помощи фабричной функции Car вы можете создавать новые объекты "car". Поведение будет таким же, как если бы вы создали класс Car вручную и определили в нем конструктор, принимающий значения "цвет" и "пробег":

>>> my_car = Car('красный', 3812.4)
>>> my_car.цвет
'красный'
>>> my_car.пробег
3812.4

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

>>> my_car[0]
'красный'
>>> tuple(my_car)
('красный', 3812.4)

    Распаковка кортежа и оператор * для распаковки аргументов функции по-прежнему работают как надо:

>>> color, mileage = my_car
>>> print(color, mileage)
красный 3812.4
>>> print(*my_car)
красный 3812.4

    К тому же в качестве бесплатного приложения вы получите приличное строковое представление своего объекта namedtuple, что позволит набирать чуть меньше текста и сэкономит на многословности:

>>> my_car
Авто(цвет='красный' , пробег=3812.4)

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

>>> my_car.цвет = 'синий'
Traceback (most recent call last):
.   .   .   .
AttributeError: can't set attribute

    На внутреннем уровне объекты namedtuple реализованы как обычные классы Python. В том, что касается использования оперативной памяти, они тоже "лучше" обычных классов и так же эффективны с точки зрения потребления оперативной памяти, как и обычные кортежи.

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

    На следующем шаге мы рассмотрим создание производных от namedtuple подклассов.




Предыдущий шаг Содержание Следующий шаг