Dev48
ЯЗЫК
  • О нас
  • Услуги
  • Индустрии
  • Технологии
  • Статьи
  • Контакты
Забронировать звонок
    Главная/Статьи/Pep 824 operatory obedineniya s none
Dev48

© 2026 · All rights reserved.

PEP 824: Операторы объединения с None

Источник: Python Enhancement Proposals (PEPs)

PEP 824: Операторы объединения с None

Источник: Python Enhancement Proposals (PEPs)

Данный PEP предлагает добавить два новых оператора.

25 сентября 2026 г.
  • Аннотация
  • Мотивация Явные проверки на None Перезапись значений None Значения по умолчанию для аргументов функций
  • Явные проверки на None
  • Перезапись значений None
  • Значения по умолчанию для аргументов функций
  • Спецификация Оператор объединения с None Приоритет Изменения в AST Изменения в грамматике Оператор присваивания с объединением с None Кэширование подвыражений Изменения в AST Изменения в грамматике
  • Оператор объединения с None Приоритет Изменения в AST Изменения в грамматике
  • Приоритет
  • Изменения в AST
  • Изменения в грамматике
  • Оператор присваивания с объединением с None Кэширование подвыражений Изменения в AST Изменения в грамматике
  • Кэширование подвыражений
  • Изменения в AST
  • Изменения в грамматике
  • Обратная совместимость
  • Последствия для безопасности
  • Как этому обучать Чтение выражений вслух Оператор объединения с None Оператор присваивания с объединением с None
  • Чтение выражений вслух Оператор объединения с None Оператор присваивания с объединением с None
  • Оператор объединения с None
  • Оператор присваивания с объединением с None
  • Эталонная реализация
  • Отложенные идеи Операторы доступа с учетом None Другие операторы условного присваивания
  • Операторы доступа с учетом None
  • Другие операторы условного присваивания
  • Отклоненные идеи Добавить новое (мягкое) ключевое слово Добавить ?? как бинарный оператор Добавить ??= как AugAssign Сделать ??= атомарным
  • Добавить новое (мягкое) ключевое слово
  • Добавить ?? как бинарный оператор
  • Добавить ??= как AugAssign
  • Сделать ??= атомарным
  • Распространенные возражения Просто используйте условное выражение Распространение None в кодовых базах None недостаточно особенный Существуют лучшие значения по умолчанию, чем None Используйте пользовательские маркеры вместо None Позднее связывание значений по умолчанию для аргументов функций
  • Просто используйте условное выражение
  • Распространение None в кодовых базах
  • None недостаточно особенный
  • Существуют лучшие значения по умолчанию, чем None
  • Используйте пользовательские маркеры вместо None
  • Позднее связывание значений по умолчанию для аргументов функций
  • Сноски
  • Авторские права

Аннотация

Данный PEP предлагает добавить два новых оператора.

  • Оператор «объединения с None» ??
  • Оператор «присваивания с объединением с None» ??=

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

Оператор «объединения с None» вычисляет левую часть, проверяет, не является ли она None, и если нет, возвращает результат. Если значение равно None, вычисляется и возвращается правая часть.

Оператор «присваивания с объединением с None» будет присваивать правую часть левой только в том случае, если левая часть вычисляется в None.

Они примерно эквивалентны:

Мотивация

Впервые официально предложенная более десяти лет назад в (ныне отложенном) PEP 505, идея добавления операторов объединения с None существует уже довольно давно и подробно обсуждалась в многочисленных ветках, в последнее время в [1] и [2]. Этот PEP призван зафиксировать текущее состояние дискуссии и предлагает спецификацию для добавления в язык Python. В отличие от PEP 505, он будет сосредоточен только на двух операторах объединения с None. Более подробную информацию см. в разделе «Отложенные идеи».

Операторы объединения с None — не новое изобретение. Несколько других современных языков программирования имеют так называемые операторы «null coalescing», включая TypeScript [3], ECMAScript (он же JavaScript) [4] [5], C# [9], Dart [11] [12], Swift [13], Kotlin [14], PHP [15] [16] и другие.

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

Явные проверки на None

В Python принято использовать None в качестве значения по умолчанию, которое нельзя спутать с другими встроенными значениями по умолчанию, такими как [], "" или 0. Большинство кода, работающего с такими функциями, либо выполняет какую-то проверку, чтобы убедиться, что действительно возвращается допустимое значение (возможно, осуществляя ранний возврат или вызывая исключение, если это не так), либо предоставляет значение по умолчанию/резервное значение. Для этого обычно используются проверки is None / is not None.

Хотя намерение ясно, это довольно многословно. Целевое имя приходится повторять несколько раз, просто чтобы иметь возможность присвоить значение по умолчанию целевой переменной. Это можно написать в более лаконичной форме, используя if-выражение. Однако у этого есть свои проблемы.

Особенно для довольно простых выражений значений нередко просто повторять их, как в примере выше, вместо использования выражения присваивания. Это может вызвать проблемы, если выражение значения имеет побочные эффекты, которые теперь будут выполнены дважды. Кроме того, не существует единого согласованного способа написания этих выражений. Вместо того чтобы ставить значение на первое место, некоторые могут предпочесть инвертировать проверку, используя is None. Читателям приходится постоянно помнить об этих сложностях, что увеличивает когнитивную нагрузку.

Использование оператора «объединения с None» ?? помогает сделать выражение коротким и предсказуемым, при этом четко передавая намерение.

Перезапись значений None

Иногда может потребоваться присвоить резервное значение внутри объекта. Для этого выражение обычно пишется дважды: один раз для проверки is None, и еще раз для присваивания.

Использование оператора «присваивания с объединением с None» ??= помогает избежать повторения выражения. Особенно для более сложных случаев это облегчит чтение и написание кода.

Значения по умолчанию для аргументов функций

Значения по умолчанию для аргументов функций вычисляются в родительской области видимости. Это распространенная проблема в случаях, когда значение по умолчанию является изменяемым объектом или зависит от самого контекста функции. В таких случаях типичным решением является разрешение None в качестве аргумента и присваивание резервного значения внутри самой функции.

Это можно переписать как:

Спецификация

Оператор объединения с None

Добавляется оператор ??. Он сначала вычисляет левую часть. Результат кэшируется, чтобы выражение не вычислялось снова. Если значение не является None, возвращается кэшированный результат. Если это None, вместо него вычисляется и возвращается выражение правой части.

Приоритет

Приоритет ?? будет ниже, чем у or, но выше, чем у условных выражений. При необходимости можно добавлять скобки для изменения приоритета отдельных выражений. Несколько примеров того, как будут расставлены неявные скобки:

Изменения в AST

Новый оператор Coalesce добавляется в boolop для использования в узлах BoolOp.

Изменения в грамматике

Добавляется новый токен ??, а также новое правило coalesce. Каждое правило, которое ранее ссылалось на правило disjunction, обновляется, чтобы вместо этого ссылаться на правило coalesce.

Оператор присваивания с объединением с None

Добавляется оператор ??=. Он выполняет условное присваивание. Таким образом, он сначала вычисляет левую часть и проверяет, является ли значение None, и только затем вычисляет и присваивает результат из правой части. Если первое значение не является None, вычисление и присваивание правой части пропускаются.

Кэширование подвыражений

Подвыражения в левой части вычисляются только один раз перед кэшированием. Это похоже на расширенные присваивания (augmented assignments).

Изменения в AST

Добавляется новый узел AST BoolAssign. Подобно AugAssign, он хранит целевое выражение и выражение значения, а также логический оператор Coalesce.

Изменения в грамматике

Добавляется новый токен ??=. Кроме того, правило присваивания расширяется, чтобы включить «присваивание с объединением с None».

Обратная совместимость

Существующие программы продолжат работать как есть. До настоящего момента код, использующий ?? или ??=, вызывал SyntaxError.

Последствия для безопасности

Данное предложение не несет новых последствий для безопасности.

Как этому обучать

В практическом смысле может быть полезно рассматривать оператор «объединения с None» ?? как частный случай условного оператора or, с той оговоркой, что ?? проверяет на «не None» вместо проверки на истинность (truthiness). Поэтому логично включать ?? при обучении другим условным операторам and и or.

Оператор «присваивания с объединением с None» ??= лучше всего рассматривать как оператор условного присваивания. Поскольку он тесно связан с ??, имеет смысл объяснять их вместе. Хотя он также визуально похож на бинарные операторы присваивания, такие как +=, стоит указать на различие между ними. Поскольку ??= является оператором условного присваивания, правая часть в некоторых случаях будет полностью пропущена, тогда как += всегда вычисляет обе стороны.

Чтение выражений вслух

Чтение выражений вслух всегда приводит к потере информации. Данный PEP не ставит целью определить однозначный способ произношения этих операторов. Поэтому следующее является лишь предложением.

Оператор объединения с None

Оператор присваивания с объединением с None

Эталонная реализация

Эталонная реализация доступна по адресу https://github.com/cdce8p/cpython/tree/pep824-none-coalescing-operators. Онлайн-демо можно протестировать по адресу https://pep823-and-pep824-demo.pages.dev/.

Отложенные идеи

Операторы доступа с учетом None

PEP 505 также предлагает добавление операторов «доступа с учетом None» ?. и ?[ ]. Поскольку операторы «объединения с None» имеют свои собственные варианты использования, операторы «доступа с учетом None» были перенесены в отдельный документ, см. PEP 823. Оба предложения могут быть приняты независимо друг от друга.

Другие операторы условного присваивания

Хотя этот PEP сосредоточен на операторе «присваивания с объединением с None», стоит отметить, что логика, лежащая в его основе, может быть легко расширена для покрытия and= / or=. Это соответствовало бы существующим операторам условного присваивания &&= и ||= в других языках программирования, таких как ECMAScript (он же JavaScript) [6] [7], Ruby [17] и Perl [18].

Отклоненные идеи

Добавление нового (мягкого) ключевого слова

У Python есть история предпочтения ключевых слов символам. Например, хотя многие языки используют && и || в качестве условных операторов, Python использует and и or соответственно. В связи с этим было предложено использовать новое (мягкое) ключевое слово, например otherwise, вместо ??.

В то время как ключевые слова and и or помогают избежать двусмысленности с бинарными операторами & и |, для ?? не существует соответствующего бинарного оператора. Более того, оба ключевых слова хорошо устоялись в разговорном и письменном языке и поэтому сразу понятны читателю. Не говоря уже о том, что они довольно короткие — всего два и три символа.

Для сравнения, новое (мягкое) ключевое слово, скорее всего, не имело бы тех же преимуществ. Для него нет устоявшегося короткого названия, поэтому, хотя можно было бы добавить такие идеи, как otherwise, они не несут в себе внутреннего смысла и по этой причине не дают немедленного преимущества. Напротив, оператор ?? хорошо известен по другим основным языкам программирования.

Наконец, использование (мягкого) ключевого слова для оператора «присваивания с объединением с None» создает дополнительные вопросы и проблемы с читаемостью.

Добавление ?? как бинарного оператора

PEP 505 изначально предлагал добавить ?? как еще один бинарный оператор. В таком случае он имел бы более высокий приоритет, чем предложенная спецификация.

Хотя это сработало бы нормально, это наводило бы на мысль, что ?? похож на другие бинарные операторы, такие как + или **. Это не так. В то время как бинарные операторы сначала вычисляют левую и правую стороны перед выполнением операции, для ?? вычисляется только левая сторона, если значение не равно None. Оператор «объединения с None» гораздо теснее связан с условными операторами or и and, которые также выполняют сокращенное вычисление (short-circuit) выражения для истинных и ложных значений соответственно.

Более того, установка приоритета между or и условными выражениями соответствует другим языкам, которые реализовали этот оператор, таким как JS [8] и C# [10].

Добавление ??= как AugAssign

PEP 505 также предлагал добавить ??= как узел AugAssign.

До сих пор AugAssign использовался только для бинарных операторов, поэтому включение ??=, который является оператором условного присваивания, было бы запутывающим. Более того, операторы AugAssign всегда вычисляют левую и правую стороны без какого-либо сокращенного вычисления. Это главное отличие по сравнению с присваиваниями «объединения с None».

Сделать ??= атомарным

Было предложено сделать оператор «объединения с None» атомарным, чтобы избежать состояний гонки, когда разные потоки пытаются использовать ??= для одной и той же цели. Поскольку оператор сначала проверяет, вычисляется ли левая сторона в None, прежде чем присваивать значение, возможно, что два потока увидят None и попытаются перезаписать друг друга.

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

Распространенные возражения

Просто используйте условное выражение

Операторы «объединения с None» можно считать синтаксическим сахаром для существующих условных выражений и операторов. В связи с этим некоторые задавались вопросом, добавят ли они что-то значимое в язык в целом.

Как показано в разделе «Мотивация», использование операторов «объединения с None» дает явные преимущества. Подытожим их еще раз:

  • Они помогают избежать повторения выражения переменной или необходимости вводить временную переменную.
  • Четкий поток управления, больше никаких if ... is not None else ... и обратных if ... is None else ... в одних и тех же блоках кода, что снижает когнитивную нагрузку при чтении кода.
  • Более лаконично и при этом более явно.

Распространение None в кодовых базах

Одной из причин, по которой PEP 505 застопорился, было то, что некоторые выражали обеспокоенность тем, как операторы «объединения с None» и «учета None» повлияют на код, написанный разработчиками. Если с значениями None станет проще работать, это побудит разработчиков использовать их чаще. Они считают, что, например, возврат необязательного значения None из функции обычно является антипаттерном. В их идеальном мире использование None было бы максимально ограничено, например, с помощью ранней проверки данных.

Безусловно, верно, что новые возможности языка влияют на то, как язык развивается в целом. Поэтому любые изменения должны рассматриваться тщательно. Однако то, что None для кого-то является антипаттерном, не помешало сообществу в целом широко его использовать. Скорее, отсутствие операторов «объединения с None» мешало разработчикам писать лаконичные выражения и часто приводило к более сложному коду, который труднее читать, чем необходимо; подробнее см. в разделе «Мотивация».

None недостаточно особенный

Некоторые упоминали, что None недостаточно особенный, чтобы оправдать выделенные операторы.

Операторы «объединения с None» были добавлены в ряд других современных языков программирования. Более того, добавление ?? и ??= предлагалось многократно с момента первого выдвижения PEP 505 более десяти лет назад.

В Python значение None часто используется для обозначения отсутствия чего-то более подходящего или отсутствующего значения. В связи с этим часто возникает необходимость целенаправленного поиска значений None, например, для предоставления значения по умолчанию или резервного значения.

Существуют более подходящие значения по умолчанию, чем None

Было отмечено, что существуют более подходящие предметно-ориентированные значения для обозначения отсутствия значения. Например, использование «» или пустой коллекции в качестве значения по умолчанию там, где это уместно, может устранить лишний код.

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

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

Используйте пользовательские маркеры (sentinels) вместо None

В Python 3.15 PEP 661 добавил возможность определять пользовательские маркеры с помощью sentinel(...). Это решило проблему в тех случаях, когда само значение None является допустимым и поэтому не может быть использовано в качестве маркера.

Однако в целом None по-прежнему будет предпочтительнее, если нужен маркер, просто потому, что он уже существует для этой конкретной цели и его проще использовать.

Позднее связывание аргументов функции по умолчанию

Некоторые предполагали, что PEP 671, который в настоящее время находится в стадии черновика и последний раз обновлялся в 2022 году, может стать лучшим решением проблемы, описанной в разделе «Значения по умолчанию для аргументов функции». Хотя это, возможно, было бы полезно в некоторых случаях, использование синтаксиса, предложенного в PEP 671, здесь просто перекладывает ответственность на более ранний этап, поскольку сама сигнатура функции должна быть изменена. Вместо user: User | None в качестве аргумента, это было бы user: User => create_default_user(). Теперь вызывающая сторона должна будет убедиться, что None никогда не передается в функцию, а аргумент вместо этого опускается.

Однако PEP 671 не может помочь в других случаях использования, таких как перезапись значений None внутри объекта, как показано в разделе «Перезапись значений None».

Сноски

Авторское право

Этот документ передан в общественное достояние или распространяется по лицензии CC0-1.0-Universal, в зависимости от того, какая из них является более разрешительной.

← Все статьи

Ещё в разделе «Разработка ПО»

Все →
Новый навык обнаруживает риски ИИ-агентов, устраняет их и доказывает эффективность исправлений
Microsoft

Новый навык обнаруживает риски ИИ-агентов, устраняет их и доказывает эффективность исправлений

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

Некоторые клиенты Supabase открывают в публичном доступе огромные массивы личных данных пользователей

Основы Blazor: SEO для веб-приложений на Blazor
Telerik

Основы Blazor: SEO для веб-приложений на Blazor

Вас затронули сокращения? Не упустите возможность приобрести пропуск Expo+ на TechCrunch Disrupt 2026 всего за 75 долларовПресса
Expo

Вас затронули сокращения? Не упустите возможность приобрести пропуск Expo+ на TechCrunch Disrupt 2026 всего за 75 долларов

Последние 24 часа, чтобы сэкономить до 200 долларов на TechCrunch Disrupt 2026. Причина 5 из 5 для участия: ИмпульсПресса
Momentum

Последние 24 часа, чтобы сэкономить до 200 долларов на TechCrunch Disrupt 2026. Причина 5 из 5 для участия: Импульс

Мы создаем Copilot как новую операционную систему для работы, охватывающую любую модель, любой форм-фактор и любую задачу. Сегодня мы объявляем о самом масштабном обновлении Copilot на сегодняшний день, объединяющем четыре компонента [Читать далее]
Microsoft

Мы создаем Copilot как новую операционную систему для работы, охватывающую любую модель, любой форм-фактор и любую задачу. Сегодня мы объявляем о самом масштабном обновлении Copilot на сегодняшний день, объединяющем четыре компонента [Читать далее]

Ещё от Python

PEP 823: Операторы доступа с учетом None
Python

PEP 823: Операторы доступа с учетом None

PEP 849: Более выразительные выражения типов
Python

PEP 849: Более выразительные выражения типов

PEP 848: Поколенческая инкрементальная сборка мусора
Python

PEP 848: Поколенческая инкрементальная сборка мусора

PEP 846: Строки документации для псевдонимов типов
Python

PEP 846: Строки документации для псевдонимов типов