Именованные кортежи присваивают имя каждому значению элемента в кортеже и тем самым создают более читаемый код. Они могут использоваться везде, где используются обычные кортежи и добавляют возможность доступа к полям по имени вместо индекса позиции.
import collections
ntuple = collections.namedtuple(typename, field_names, *, \
rename=False, defaults=None, module=None)
typename
- строка, имя именованного кортежа,field_names
- последовательность строк, имена элементов кортежа,rename
- bool
, авто-переименование повторяющихся имен элементов,defaults=None
- итерируемая последовательность, значения по умолчанию имен кортежа,module=None
- атрибут __module__
именованного кортежа.Класс namedtuple()
модуля collections
возвращает новый подкласс кортежа с именем typename
. Новый подкласс используется для создания объектов, похожих на кортежи, которые имеют индексируемые и итерируемые поля, доступные для поиска по атрибутам. Экземпляры подкласса также имеют полезную строку документации с typename
и field_names
, а так же метод __repr__()
, который перечисляет содержимое кортежа в формате name=value
.
Имена полей field_names
представляют собой последовательность строк, таких как ['x', 'y']
. В качестве альтернативы, field_names
может быть одной строкой, в которой каждое имя поля разделено пробелами и/или запятыми, например, 'x y'
или 'x, y'
.
Для имен полей (элементов кортежа) может использоваться любой действительный идентификатор Python, за исключением имен, начинающихся с подчеркивания. Допустимые идентификаторы состоят из букв, цифр и символов подчеркивания, но не начинаются с цифры или символа подчеркивания и не могут быть ключевыми словами, такими как class
, for
, return
, global
, pass
и т. д.
Если аргумент rename=True
, то недопустимые имена полей автоматически заменяются позиционными именами. Например ['abc', 'def', 'ghi', 'abc']
преобразуется в ['abc', '_1', 'ghi', '_3']
, исключая ключевое слово def
и повторяющееся имя поля abc
.
Значения аргумента defaults
могут быть None
или итерируемой последовательностью. Поскольку аргумента со значением по умолчанию должны идти после любых обязательных аргументов, то значения по умолчанию будут применяются к самым правым параметрам. Например, если имена полей именованного кортежа это ['x', 'y', 'z']
, а значения по умолчанию (1, 2)
, то тогда x
будет обязательным аргументом, y
по умолчанию будет 1, а z
будет 2.
Если аргумент module
определен, то атрибуту именованного кортежа __module__
присваивается значение module
.
Экземпляры именованных кортежей не имеют словарей, поэтому они легковесны и требуют не больше памяти, чем обычные кортежи.
# Простой пример
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
# создаем с позиционным или именованным параметром
>>> p = Point(11, y=22)
# можно обращаться по индексу
# как к обычному кортежу
>>> p[0] + p[1]
# 33
# распаковать как обычный кортеж
>>> x, y = p
>>> x, y
# (11, 22)
# поля также доступны по названию
>>> p.x + p.y
# 33
# человеко-читаемый __repr__
>>> p
# Point(x=11, y=22)
Именованные кортежи поддерживают функцию getattr()
:
>>> getattr(p, 'x')
# 11
В дополнение к методам, унаследованным от кортежей, именованные кортежи поддерживают три дополнительных метода и два атрибута. Чтобы избежать конфликтов с именами полей, имена методов и атрибутов начинаются с подчеркивания.
NamedTuple
, атрибуты и методы:NamedTuple._make(iterable)
:Метод NamedTuple._make()
создает новый экземпляр класса namedtuple()
из существующей последовательности или итерации iterable
.
>>> t = [11, 22]
>>> Point._make(t)
# Point(x=11, y=22)
NamedTuple._asdict()
:Метод NamedTuple._asdict()
вернет новый словарь dict
, который отображает имена полей в соответствии с их значениями:
>>> p = Point(x=11, y=22)
>>> p._asdict()
# {'x': 11, 'y': 22}
NamedTuple._replace(**kwargs)
:Метод NamedTuple._replace()
вернет новый экземпляр именованного кортежа, заменив указанные поля новыми значениями:
>>>
>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
# Point(x=33, y=22)
>>> for partnum, record in inventory.items():
... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
NamedTuple._fields
:Свойство NamedTuple._fields
вернет кортеж строк, перечисляющий имена полей. Полезно для самоанализа и для создания новых именованных типов кортежей из существующих именованных кортежей.
# просмотр имен полей
>>> p._fields
# ('x', 'y')
# создание нового именованного кортежа
# на основе Pixel (созданного ранее) и Color
>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
# Pixel(x=11, y=22, red=128, green=255, blue=0)
NamedTuple._field_defaults
:Свойство NamedTuple._field_defaults
вернет словарь, который сопоставляет имена полей со значениями по умолчанию.
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
# {'balance': 0}
>>> Account('premium')
# Account(type='premium', balance=0)
Чтобы преобразовать словарь в именованный кортеж, используйте оператор двойной звезды **
как описано в разделе "Распаковка списков аргументов":
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
# Point(x=11, y=22)
Именованные кортежи особенно полезны для присвоения имен полей в результате кортежей, возвращаемых модулями csv
или sqlite3
:
from collections import namedtuple
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, \
title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
Поскольку именованный кортеж является обычным классом Python, его легко добавить или изменить с помощью подкласса. Вот как добавить вычисляемое поле и формат печати фиксированной ширины:
from collections import namedtuple
class Point(namedtuple('Point', ['x', 'y'])):
__slots__ = ()
@property
def hypot(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
def __str__(self):
return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
for p in Point(3, 4), Point(14, 5/7):
print(p)
# Point: x=3.000 y=4.000 hypot=5.000
# Point: x=14.000 y=0.714 hypot=14.018
Подкласс, показанный выше, устанавливает __slots__
в пустой кортеж. Это помогает снизить требования к памяти, предотвращая создание словарей экземпляров.
Подклассы бесполезны для добавления новых полей. Вместо этого просто создайте новый именованный тип кортежа из атрибута _fields
:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
>>> Point3D(10, 20, 30)
Point3D(x=10, y=20, z=30)
Строки документов могут быть настроены путем прямого назначения значения атрибуту __doc__
:
>>> from collections import namedtuple
>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'