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

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы задать значения по умолчанию для полей вашего именованного кортежа (NamedTuple), воспользуйтесь модулями collections и dataclasses, которые доступны начиная с Python версии 3.7+. Пример кода выглядит так:

Python
Скопировать код
from typing import NamedTuple
from dataclasses import dataclass, field

@dataclass
class Point(NamedTuple):
    x: int = field(default=0)  # Определяем координату X по умолчанию как 0
    y: int = field(default=0)  # Определяем координату Y по умолчанию как 0

# Значения по умолчанию: Point(x=0, y=0)
# Пользовательские значения: Point(x=5, y=10)

Этот подход сочетает в себе удобство назначения значений по умолчанию и простоту определения именованного кортежа.

Кинга Идем в IT: пошаговый план для смены профессии

Применение значений по умолчанию в более ранних версиях Python

Установка значений по умолчанию в более ранних версиях Python

Если у вас установлена версия Python 3.7 или более ранняя, процесс задания значений по умолчанию может вам показаться немного сложным:

Python
Скопировать код
from collections import namedtuple

Node = namedtuple('Node', 'value left right')

# Пришло время задать значения по умолчанию!
Node.__new__.__defaults__ = (None, None, None)  # На Python 3.6

Если же вы используете версию Python ранее 3.6, то __defaults__ следует заменить на func_defaults:

Python
Скопировать код
Node.__new__.func_defaults = (None,) * len(Node._fields)  # Это будто археологическая находка!

Переопределение метода __new__

Если стандартный подход вам не кажется оптимальным, можно переопределить метод __new__ в подклассе NamedTuple, устанавливая свои значения по умолчанию:

Python
Скопировать код
class Node(namedtuple('NodeBase', 'value, left, right')):
    def __new__(cls, value, left=None, right=None):
        return super(Node, cls).__new__(cls, value, left, right)

Прототипирование: предвкушение будущего

Почувствуйте себя создателем! Сформируйте прототип и задайте значения по умолчанию с помощью метода _replace:

Python
Скопировать код
prototype_node = Node(None, None, None)  # Встречайте наш прототип Node!

# Пришла пора создать новый узел (или экземпляр Node)!
new_node = prototype_node._replace(value='root')

Определение типов с использованием аннотаций типов и значений по умолчанию

Совершенствование типизации в Python 3.6.1+

В Python 3.6.1+ значительно улучшена поддержка значений по умолчанию в typing.NamedTuple, что делает код более читабельным и привлекательным:

Python
Скопировать код
from typing import NamedTuple

class Point(NamedTuple):
    x: int = 0
    y: int = 0

Data classes: новое слово в Python

Классы данных появились в Python 3.7 и быстро стали полезной заменой именованным кортежам для более сложных структур:

Python
Скопировать код
from dataclasses import dataclass

@dataclass
class Point:
    x: int = 0
    y: int = 0

Визуализация

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

Python
Скопировать код
from collections import namedtuple

Ingredient = namedtuple('Ingredient', 'name quantity', defaults=[None, '1 spoon'])

# Приступим к приготовлению!
sugar = Ingredient('sugar')
flour = Ingredient('flour', '2 cups')

Для наглядности представим рецепт десерта в виде таблицы:

Markdown
Скопировать код
Рецепт приготовления торта 🎂

| Ингредиент | Количество (по умолчанию) |
| ---------- | ----------------------    |
| Сахар      | 1 ложка (✅)              |
| Мука       | 2 стакана (🔄)            |

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

Расширенные методы и способы избежать ошибок

Использование slots: ограничение динамических атрибутов

Чтобы избежать создания динамических словарей для экземпляров, что может быть неэффективно во время работы с памятью, используйте __slots__ в подклассах namedtuple:

Python
Скопировать код
class SlotNode(NamedTuple):
    __slots__ = ()  # Политика 'нетрогай'
    value: int
    left: 'SlotNode' = None
    right: 'SlotNode' = None

Будущее уже здесь: прямая типизация

В Python 3.7+ уже нет необходимости заключать типы в кавычки. Это стало возможным благодаря импорту из __future__:

Python
Скопировать код
from __future__ import annotations

class Tree(NamedTuple):
    left: Tree | None = None
    right: Tree | None = None

Корректировка ситуации с помощью обертывающей функции

Обертывающая функция может работать как с позиционными, так и с ключевыми аргументами, заданными по умолчанию, будто она супергерой, спасающий мир:

Python
Скопировать код
def namedtuple_with_defaults(typename, field_names, default_values=()):
    T = namedtuple(typename, field_names)
    T.__new__.__defaults__ = (None,) * len(T._fields)  # Все под контролем
    if isinstance(default_values, dict):
        prototype = T(**default_values)
    else:
        prototype = T(*default_values)
    T.__new__.__defaults__ = prototype
    return T

Полезные материалы

  1. collections — Container datatypes — Python 3.9.4 documentation — Официальная документация Python по работе с именованными кортежами.
  2. python – Named tuple and default values for optional keyword arguments – Stack Overflow — Обсуждение возможностей NamedTuple и значений по умолчанию на форуме Stack Overflow.
  3. dataclasses — Data Classes — Python 3.9.4 documentation — Информация о классах данных в версии Python 3.7+ и о применении значений по умолчанию.
  4. python – How to check if an object is an instance of a namedtuple? – Stack Overflow — Обсуждение неизменности именованных кортежей на форуме Stack Overflow.
  5. isbn:1788294874 – Google Books — Упоминание книги с рекомендациями по использованию языка Python, включая информацию об именованных кортежах.