NamedTuple в Python

02 октября 2026
Автор

Антон Ларичев

Что такое NamedTuple

Обычный кортеж хранит данные по индексу, и со временем это становится проблемой: непонятно, что означает point[0] — координата X, ID или что-то ещё. NamedTuple решает эту проблему, добавляя имена к каждому полю кортежа.

NamedTuple — это подкласс обычного кортежа. Он сохраняет все свойства кортежа (неизменяемость, поддержку индексирования, распаковку), но при этом позволяет обращаться к элементам по имени.

В Python есть два способа создать именованный кортеж:

  • collections.namedtuple — функциональный способ, доступен с Python 2.6
  • typing.NamedTuple — классовый синтаксис с поддержкой аннотаций типов, доступен с Python 3.6

Курс по теме

Основы Python — курс

40 000+ студентов · рейтинг 4.8 · гарантия возврата 30 дней

collections.namedtuple

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

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])

p = Point(10, 20)
print(p.x)   # 10
print(p.y)   # 20
print(p[0])  # 10 — индексирование по-прежнему работает
print(p)     # Point(x=10, y=20)

Поля можно передать строкой через пробел или запятую:

Point = namedtuple('Point', 'x y')
Color = namedtuple('Color', 'red, green, blue')

Значения по умолчанию

С Python 3.6.1 в namedtuple появился параметр defaults. Значения по умолчанию применяются к последним N полям:

from collections import namedtuple

HTTPResponse = namedtuple(
    'HTTPResponse',
    ['status', 'body', 'headers'],
    defaults=[None, {}]  # применяется к body и headers
)

response = HTTPResponse(status=200)
print(response.body)     # None
print(response.headers)  # {}

response2 = HTTPResponse(status=404, body='Not Found')
print(response2)  # HTTPResponse(status=404, body='Not Found', headers={})

typing.NamedTuple

Классовый синтаксис через typing.NamedTuple более читаем и поддерживает аннотации типов, документирование и значения по умолчанию прямо в теле класса.

from typing import NamedTuple

class Point(NamedTuple):
    x: float
    y: float

p = Point(1.5, 2.7)
print(p.x)  # 1.5
print(p)    # Point(x=1.5, y=2.7)

Значения по умолчанию в классовом стиле

from typing import NamedTuple

class HTTPResponse(NamedTuple):
    status: int
    body: str | None = None
    headers: dict = {}

response = HTTPResponse(status=200)
print(response)  # HTTPResponse(status=200, body=None, headers={})

Методы в typing.NamedTuple

Одно из главных преимуществ классового синтаксиса — возможность добавлять методы:

from typing import NamedTuple
import math

class Point(NamedTuple):
    x: float
    y: float

    def distance_to(self, other: 'Point') -> float:
        return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)

    def __str__(self) -> str:
        return f'Point({self.x}, {self.y})'

a = Point(0, 0)
b = Point(3, 4)
print(a.distance_to(b))  # 5.0

Встроенные методы NamedTuple

Все именованные кортежи, независимо от способа создания, получают набор встроенных методов.

_fields

Атрибут _fields возвращает кортеж с именами всех полей:

from typing import NamedTuple

class User(NamedTuple):
    name: str
    age: int
    email: str

print(User._fields)  # ('name', 'age', 'email')

_asdict

Метод _asdict преобразует именованный кортеж в словарь:

user = User(name='Alice', age=30, email='alice@example.com')
d = user._asdict()
print(d)  # {'name': 'Alice', 'age': 30, 'email': 'alice@example.com'}

# Удобно для сериализации
import json
print(json.dumps(user._asdict()))  # {"name": "Alice", "age": 30, "email": "alice@example.com"}

_replace

Поскольку кортежи неизменяемы, _replace создаёт новый экземпляр с изменёнными полями:

user = User(name='Alice', age=30, email='alice@example.com')
updated_user = user._replace(age=31)

print(user)          # User(name='Alice', age=30, email='alice@example.com')
print(updated_user)  # User(name='Alice', age=31, email='alice@example.com')

_make

Классметод _make создаёт именованный кортеж из любого итерируемого объекта:

data = ['Bob', 25, 'bob@example.com']
user = User._make(data)
print(user)  # User(name='Bob', age=25, email='bob@example.com')

# Очень удобно при чтении данных из CSV или БД
rows = [
    ('Alice', 30, 'alice@example.com'),
    ('Bob', 25, 'bob@example.com'),
]
users = [User._make(row) for row in rows]

Неизменяемость и поведение кортежа

NamedTuple — полноценный кортеж. Попытка изменить поле вызовет AttributeError:

point = Point(1.0, 2.0)
point.x = 5.0  # AttributeError: can't set attribute

При этом все кортежные операции работают:

point = Point(3.0, 4.0)

# Распаковка
x, y = point
print(x, y)  # 3.0 4.0

# Индексирование
print(point[0])   # 3.0

# Итерация
for value in point:
    print(value)

# Использование как ключа словаря
cache = {}
cache[point] = 'origin'

# Сравнение
p1 = Point(1.0, 2.0)
p2 = Point(1.0, 2.0)
print(p1 == p2)  # True

Практические примеры использования

Возврат нескольких значений из функции

Вместо словаря или обычного кортежа именованный кортеж делает намерение явным:

from typing import NamedTuple

class ParseResult(NamedTuple):
    host: str
    port: int
    path: str

def parse_url(url: str) -> ParseResult:
    # упрощённый парсер для примера
    parts = url.split('/')
    host_port = parts[2].split(':')
    host = host_port[0]
    port = int(host_port[1]) if len(host_port) > 1 else 80
    path = '/' + '/'.join(parts[3:])
    return ParseResult(host=host, port=port, path=path)

result = parse_url('http://example.com:8080/api/users')
print(result.host)  # example.com
print(result.port)  # 8080
print(result.path)  # /api/users

Работа с CSV и табличными данными

import csv
from typing import NamedTuple

class Product(NamedTuple):
    name: str
    price: float
    quantity: int

def load_products(filename: str) -> list[Product]:
    products = []
    with open(filename) as f:
        reader = csv.reader(f)
        next(reader)  # пропускаем заголовок
        for row in reader:
            products.append(Product(
                name=row[0],
                price=float(row[1]),
                quantity=int(row[2])
            ))
    return products

# Работа с данными
products = [
    Product('Laptop', 999.99, 5),
    Product('Mouse', 29.99, 50),
    Product('Keyboard', 79.99, 30),
]

total_value = sum(p.price * p.quantity for p in products)
expensive = [p for p in products if p.price > 50]

print(f'Общая стоимость: {total_value:.2f}')
print(f'Дорогие товары: {[p.name for p in expensive]}')

Конфигурация приложения

from typing import NamedTuple

class DatabaseConfig(NamedTuple):
    host: str
    port: int
    name: str
    user: str
    password: str
    pool_size: int = 5
    timeout: int = 30

DEV_CONFIG = DatabaseConfig(
    host='localhost',
    port=5432,
    name='myapp_dev',
    user='dev',
    password='devpass'
)

PROD_CONFIG = DEV_CONFIG._replace(
    host='prod-db.example.com',
    name='myapp_prod',
    user='prod_user',
    password='secure_password',
    pool_size=20
)

def connect(config: DatabaseConfig):
    print(f'Connecting to {config.host}:{config.port}/{config.name}')

NamedTuple vs dataclass vs dict

Выбор между этими структурами зависит от задачи.

from typing import NamedTuple
from dataclasses import dataclass

# Словарь — нет типизации, мутируемый
point_dict = {'x': 1.0, 'y': 2.0}

# NamedTuple — иммутируемый, лёгкий, типизированный
class PointNT(NamedTuple):
    x: float
    y: float

# dataclass — мутируемый по умолчанию, гибкий
@dataclass
class PointDC:
    x: float
    y: float
Критерий dict NamedTuple dataclass
Иммутируемость Нет Да Опционально (frozen=True)
Аннотации типов Нет Да Да
Использование как ключ словаря Нет Да Только с frozen=True
Методы Нет Да Да
Потребление памяти Высокое Низкое Среднее
Совместимость с tuple Нет Да Нет
Наследование Нет Ограниченное Да

Производительность

NamedTuple потребляет меньше памяти, чем dict или dataclass, потому что хранит данные в кортеже без дополнительного __dict__:

import sys
from typing import NamedTuple
from dataclasses import dataclass

class PointNT(NamedTuple):
    x: float
    y: float

@dataclass
class PointDC:
    x: float
    y: float

nt = PointNT(1.0, 2.0)
dc = PointDC(1.0, 2.0)
d = {'x': 1.0, 'y': 2.0}

print(sys.getsizeof(nt))  # ~56 байт
print(sys.getsizeof(dc))  # ~48 байт (но dc.__dict__ добавляет ~200+ байт)
print(sys.getsizeof(d))   # ~200+ байт

Ограничения NamedTuple

Перед использованием NamedTuple важно понимать его ограничения.

Нельзя изменять поля после создания. Это особенность, а не баг, но если данные должны меняться — лучше использовать dataclass.

Ограниченное наследование. Нельзя добавить новые поля в подклассе:

from typing import NamedTuple

class Base(NamedTuple):
    x: int
    y: int

# Это не добавит поле z — поведение непредсказуемо
class Extended(Base):
    z: int  # это не поле NamedTuple, а просто аннотация класса

e = Extended(1, 2)  # TypeError: __new__() takes 3 positional arguments but 4 were given

Сравнение происходит по значениям, а не по типу:

from typing import NamedTuple

class Point(NamedTuple):
    x: float
    y: float

class Vector(NamedTuple):
    x: float
    y: float

p = Point(1.0, 2.0)
v = Vector(1.0, 2.0)

print(p == v)  # True — сравниваются как кортежи (1.0, 2.0) == (1.0, 2.0)

Если нужно различать типы при сравнении, используйте dataclass.

Когда использовать NamedTuple

NamedTuple — правильный выбор, когда:

  • данные не должны изменяться после создания
  • нужна совместимость с кортежем (распаковка, использование как ключ словаря, передача в функции, ожидающие tuple)
  • важна минимальная нагрузка на память при большом количестве объектов
  • нужно вернуть несколько значений из функции с явными именами
  • данные представляют собой простую запись без сложной бизнес-логики

Для мутируемых структур с наследованием и валидацией лучше подойдёт dataclass. Для данных с валидацией и сериализацией рассмотрите Pydantic.


Чтобы глубже разобраться в Python и структурах данных, записывайтесь на курс по Python на PurpleSchool: https://purpleschool.ru/course/python?utm_source=knowledgebase&utm_medium=text&utm_campaign=python-namedtuple

Стрелочка влевоPolars — работа с большими данными в Python

Постройте личный план изучения Python до уровня Middle — бесплатно!

Python — часть карты развития Backend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Все гайды по Python

Как отправлять запросы с помощью requests в PythonПочему Python выводит значение без команды printВозможности Python для автоматизации задачКак работает команда print в PythonРабота с JSON в Python на примерахКак находить и исправлять ошибки в PythonPython get — методы получения данныхСтруктура и оформление кода PythonРабота с данными через API и внешние сервисыОсновы Django с PythonПолезные приёмы в Python для повседневной работыИспользование locals в Python для отладкиИнтеграция PHP и PythonКак выполнять HTTPS-запросы в PythonFastAPI Python — быстрый старт: создание REST API с нуляКак работать с API в Python
Ввод целого числа в PythonВедение логов в PythonУдаление данных в Python с помощью removeОбработка исключений с помощью try/except в PythonФункция super() в Python — как вызвать метод родителяРабота с переменной X в PythonСоздание собственных контекстных менеджеров в PythonРабота с классами в PythonКак скачать Python на компьютерРабота с символами программирования PythonПростая программа на Python для начинающихОсновы Python для тех, кто начинаетЧто нового в Python 3Поддерживается ли Python 2 и стоит ли его использоватьPython 1 — с чего начиналась история языкаКоманда python print - полное руководство по выводу данныхПравила именования переменных в PythonПользовательские исключения в PythonОсновы Python coreОписание объектов PythonНаследование классов в Python — основы и примерыМножественное наследование в Python — примеры и MROКонтекстный менеджер with в Python — как работает и зачем нуженКомментарии в Python — однострочные, многострочные и docstringКакой Python выбрать для установкиКак вывести целое число с помощью print в PythonКак установить Python на Windows macOS и LinuxКак пользоваться консолью PythonКак получить последний элемент в PythonКак найти значение в PythonКак настроить PythonКак использовать print для строк в PythonКак работает интерпретатор PythonИнструкция по работе с PythonБлок finally в обработке исключений PythonЦелые числа в PythonАбстрактные классы в Python — ABC и abstractmethod
Загрузка данных PythonУправление проектами на GitHub с PythonСоздание веб-приложений на Flask PythonСоздание бота на PythonСоздание интерфейсов Python QTСоздание игр с PygameСоздание GUI в PythonКак работать со словарями в PythonРабота с библиотеками через Python PackagingРабота со временем в Python при помощи модуля timePython name — особенности переменнойМатематические операции в Python с модулем mathPython listing — что это и как использоватьОбработка изображений с OpenCV PythonPytest — тестирование на Python: полное руководствоNumPy в Python — основы и применение в задачахМашинное обучение с PythonИспользование Anaconda с PythonМодуль contextlib в Python — утилиты для контекстных менеджеровБиблиотеки Python и их применение в проектах
Возврат значений из функции в PythonВложенные функции в PythonСоздание собственных декораторов в PythonРабота с функцией map в PythonЦикл while в Python и примеры использованияОбработка чисел, введённых через input в PythonОсновные операторы в Python с примерамиУсловные выражения if else в Python для начинающихКак выполняется вызов функций call в PythonПродвинутые генераторы в Python — send, throw, close и корутиныПозиционные и именованные аргументы в PythonОбъявление переменных и управление областью видимости в PythonПередача аргументов по ссылке и по значению в PythonПередача аргументов через args и kwargs в PythonОсновные методы Python и примеры их использованияОператор match/case в Python 3.10+ — основы структурного сопоставленияПаттерны match/case в Python — деструктуризация, guard и вложенные шаблоныЛокальные и глобальные переменные в PythonПрактические примеры match/case в Python — реальные сценарии примененияЧасто используемые команды PythonКлючевые слова global и nonlocal в PythonКак создавать функции в PythonКак работает сборщик мусора в PythonКак работает область видимости переменных в PythonКак работает функция callable в PythonКак работает функция any и all в PythonКак проверить тип переменной в PythonКак передать функцию как аргумент в PythonКак использовать функцию isinstance в PythonКак использовать функцию filter в PythonКак использовать функцию filter в PythonКак использовать декораторы в PythonКак использовать функцию eval безопасно в PythonИзменяемые и неизменяемые типы данных в PythonГенераторные выражения в Python — синтаксис и примерыФункции в Python и способы их вызоваЧто такое замыкания в PythonГенераторы и yield в Python — как создавать и использоватьЧто делает функция reduce в PythonФункции как объекты в PythonЧто делает функция id в PythonАргументы по умолчанию в PythonАнонимные функции и lambda в PythonАлгоритмы на Python — примеры и объяснение
Запись данных в PythonУправление зависимостями requirement в PythonУстановка pip в PythonУправление библиотеками с помощью Python PackagingУдаление пробелов с помощью strip в PythonСтруктурирование кода в PythonСоздание исполняемого файла Python в exeРазбор traceback в модуле PythonРазбор site-packages в PythonРазбор Program Files в PythonРабота с Unicode кодировками в PythonРабота с системными функциями Python sysРабота с модулем logging в PythonРабота с папкой AppData в PythonРабота с каталогами в PythonВиртуальная среда venv в Python — создание и настройкаКак создать простое приложение на PythonРабота с CSV в PythonИспользование pip в Python для установки пакетовМодули в Python и организация кода в проектеИмпорт модулей в Python и правила подключенияРабота с файлами в Python пошаговоЧто делает компилятор Python и как он работаетПолучение строки из модуля PythonПодключение файлов в Python с includeПеременные среды в PythonСборка проекта с помощью packaging в PythonНастройка Python сервераИспользование Python на UbuntuИспользование консоли PythonИспользование кодировок в PythonИнициализация пакетов PythonИмпорт модулей PythonИмпорт имен в PythonСреда IDLE Python и базовые возможностиЧтение и запись TXT в PythonЧтение файлов в Python с помощью open file
Удаление элементов из списка PythonТипы данных в Python — обзор и рекомендацииОсновные операции со строками в PythonМетоды str в Python и обработка текстаСписки в Python и их ключевые методыСоздание списков данных в PythonРабота со строками и символами в PythonРабота со столбцами в PythonРабота со списком значений в PythonРабота с таблицами в Python с помощью DataFrameРабота с RFR в PythonРабота с пробелами в PythonРабота с массивами в PythonРабота с кортежами tuple PythonРабота с координатами X и Y в PythonРабота с ключами в PythonРабота с элементами данных PythonРабота с двоичными числами PythonРабота с данными в PythonРабота с данными NumPy PythonРабота с большими числами в PythonРабота с битами в PythonРабота с байтами в PythonМножества в Python и операции с нимиЧто такое значение в Python и как его определитьИспользование range в Python для цикловПроверка на четность в PythonПроверка числа в PythonПреобразование типов в PythonПреобразование списка в строку PythonПреобразование числа в строку в PythonПостроение графиков в PythonОпределение индекса элемента в PythonОкругление чисел в PythonОбъединение списков в Python с помощью zipМножества в PythonМассивы в Python и отличие от списковМассив чисел в PythonКортежи данных в PythonКак вычислить сумму чисел в PythonКак получить остаток от деления в PythonКак найти следующее число в PythonИспользование Unicode в PythonТип int в Python и его особенностиИндекс списка в PythonФункции для работы со строками в PythonЭлементы Python и способы доступа к нимДоступ к элементам массива в PythonДеление чисел в PythonРабота с данными в Python на практикеКак работать с числами в Python
Открыть базу знаний

Лучшие курсы по теме

Иконка молнииНовый
изображение курса

Основы Python

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий