Автор оригинала: Doug Hellmann.
Стандартный tuple
использует числовые индексы для доступа к своим членам.
collections_tuple.py
bob ('Bob', 30, 'male') print('Representation:', bob) jane ('Jane', 29, 'female') print('\nField by index:', jane[0]) print('\nFields by index:') for p in [bob, jane]: print('{} is a {} year old {}'.format(*p))
Это делает кортежи
удобными контейнерами для простого использования.
$ python3 collections_tuple.py Representation: ('Bob', 30, 'male') Field by index: Jane Fields by index: Bob is a 30 year old male Jane is a 29 year old female
Напротив, запоминание того, какой индекс следует использовать для каждого значения, может привести к ошибкам, особенно если кортеж
имеет много полей и построен далеко от того места, где он используется. namedtuple
назначает имена, а также числовой индекс каждому члену.
Определение
Экземпляры namedtuple
так же эффективны с точки зрения памяти, как и обычные кортежи, поскольку у них нет словарей для каждого экземпляра. Каждый вид namedtuple
представлен своим собственным классом, который создается с помощью фабричной функции namedtuple ()
. Аргументы – это имя нового класса и строка, содержащая имена элементов.
collections_namedtuple_person.py
import collections Person collections.namedtuple('Person', 'name age') bob Person(name'Bob', age30) print('\nRepresentation:', bob) jane Person(name'Jane', age29) print('\nField by name:', jane.name) print('\nFields by index:') for p in [bob, jane]: print('{} is {} years old'.format(*p))
Как показано в примере, можно получить доступ к полям namedtuple
по имени, используя точечную нотацию ( obj.attr
), а также используя позиционные индексы стандартных кортежей.
$ python3 collections_namedtuple_person.py Representation:, Field by name: Jane Fields by index: Bob is 30 years old Jane is 29 years old
Как и обычный кортеж
, namedtuple
неизменяем. Это ограничение позволяет экземплярам tuple
иметь согласованное хэш-значение, что позволяет использовать их в качестве ключей в словарях и включать в наборы.
collections_namedtuple_immutable.py
import collections Person collections.namedtuple('Person', 'name age') pat Person(name'Pat', age12) print('\nRepresentation:', pat) pat.age 21
Попытка изменить значение с помощью его именованного атрибута приводит к ошибке AttributeError
.
$ python3 collections_namedtuple_immutable.py Representation:, Traceback (most recent call last): File "collections_namedtuple_immutable.py", line 17, inpat.age = 21 AttributeError: can't set attribute
Недействительные имена полей
Имена полей недействительны, если они повторяются или конфликтуют с ключевыми словами Python.
collections_namedtuple_bad_fields.py
import collections try: collections.namedtuple('Person', 'name class age') except ValueError as err: print(err) try: collections.namedtuple('Person', 'name age age') except ValueError as err: print(err)
При анализе имен полей недопустимые значения вызывают исключения ValueError
.
$ python3 collections_namedtuple_bad_fields.py Type names and field names cannot be a keyword: 'class' Encountered duplicate field name: 'age'
В ситуациях, когда namedtuple
создается на основе значений, находящихся вне контроля программы (например, для представления строк, возвращаемых запросом к базе данных, где схема заранее не известна), параметр переименовать
должен быть установлен на True
, чтобы недопустимые поля были переименованы.
collections_namedtuple_rename.py
import collections with_class collections.namedtuple( 'Person', 'name class age', renameTrue) print(with_class._fields) two_ages collections.namedtuple( 'Person', 'name age age', renameTrue) print(two_ages._fields)
Новые имена для переименованных полей зависят от их индекса в кортеже, поэтому поле с именем class
становится _1
, а повторяющееся поле age
изменяется. в _2
.
$ python3 collections_namedtuple_rename.py ('name', '_1', 'age') ('name', 'age', '_2')
Особые атрибуты
namedtuple
предоставляет несколько полезных атрибутов и методов для работы с подклассами и экземплярами. Все эти встроенные свойства имеют имена с префиксом подчеркивания ( _
), который по соглашению в большинстве программ Python указывает на частный атрибут. Однако для namedtuple
префикс предназначен для защиты имени от столкновения с указанными пользователем именами атрибутов.
Имена полей, переданные в namedtuple
для определения нового класса, сохраняются в атрибуте _fields
.
collections_namedtuple_fields.py
import collections Person collections.namedtuple('Person', 'name age') bob Person(name'Bob', age30) print('Representation:', bob) print('Fields:', bob._fields)
Хотя аргумент представляет собой одну строку, разделенную пробелами, сохраненное значение представляет собой последовательность отдельных имен.
$ python3 collections_namedtuple_fields.py Representation:, Fields: ('name', 'age')
Экземпляры namedtuple
можно преобразовать в экземпляры OrderedDict
с помощью _asdict ()
.
collections_namedtuple_asdict.py
import collections Person collections.namedtuple('Person', 'name age') bob Person(name'Bob', age30) print('Representation:', bob) print('As Dictionary:', bob._asdict())
Ключи OrderedDict
находятся в том же порядке, что и поля для namedtuple
.
$ python3 collections_namedtuple_asdict.py Representation:, As Dictionary: OrderedDict([('name', 'Bob'), ('age', 30)])
Метод _replace ()
создает новый экземпляр, заменяя значения некоторых полей в процессе.
collections_namedtuple_replace.py
import collections Person collections.namedtuple('Person', 'name age') bob Person(name'Bob', age30) print('\nBefore:', bob) bob2 bob._replace(name'Robert') print('After:', bob2) print('Same?:', bob is bob2)
Хотя название подразумевает, что он изменяет существующий объект, поскольку экземпляры namedtuple
неизменяемы, метод фактически возвращает новый объект.
$ python3 collections_namedtuple_replace.py Before:, After:, Same?: False