НОВОСТИ

Позволяет Python-библиотекам отличить пропущенный аргумент от намеренно переданного None.

На этой странице 2 раздела

Обычно Python-разработчику достаточно None. Но автору библиотеки иногда нужно различить два события: вызывающий код явно передал None или не передал ничего. Если использовать None для обоих случаев, API может проигнорировать требование сбросить значение, приняв его за отсутствие аргумента. Значения по умолчанию, частичные обновления и многослойные настройки становятся неоднозначными.

Локальный MISSING = object() работает внутри одного модуля, а dataclasses.MISSING и attrs.NOTHING принадлежат своим фреймворкам. Взаимодействующим библиотекам нужен общий независимый маркер с публичным типом.

denial — небольшая Python-библиотека, которая даёт второму состоянию специальное значение-маркер. Такие значения также называют сентинелами. InnerNone означает «значение не передано» внутри библиотечного кода, а обычный None остаётся полноценным пользовательским значением. Релиз доступен на GitHub.

Как используется InnerNone

Распространённый пример — API, где пропуск означает «унаследовать текущее значение», а None — «явно очистить»:

from typing import Union

from denial import InnerNone, InnerNoneType

Timeout = Union[int, None, InnerNoneType]

def resolve_timeout(value: Timeout = InnerNone):
    if value is InnerNone:
        return inherited_timeout()
    return value  # None означает «явно отключено».

То же различие встречается в API частичных обновлений, слоях конфигурации, кэшах и значениях по умолчанию. InnerNone — внутреннее состояние библиотеки, а не пользовательское значение.

API намеренно мал: InnerNone — общее значение, а InnerNoneType можно использовать в аннотациях и проверках isinstance. Для проверки идентичности служит value is InnerNone.

Маркер нужно сравнивать через is, как в примере. Это одно общее значение для взаимодействующих библиотек, а не средство создания множества разных маркеров.

Когда лучше выбрать фабрику маркеров

sentinel-value и sentinels предоставляют фабрики и более надёжную сериализацию, поэтому лучше подходят проектам с несколькими маркерами. denial стандартизирует один маркер и публичный тип для взаимодействующих библиотек.

PEP 661 — предложение добавить стандартный API для таких маркеров — пока отложено. Будущий стандарт может дать общий интерфейс, но старым версиям Python и проектам с особым смыслом маркеров всё равно потребуются отдельные реализации.