Did you forget parentheses around the comprehension target: что значит ошибка и как исправить

Did you forget parentheses around the comprehension target: что значит ошибка и как исправить Полезное

SyntaxError: did you forget parentheses around the comprehension target? — это сообщение, которое Python 3.10 и новее выдает, когда внутри спискового или множественного включения перед for стоят несколько значений через запятую без скобок: [n, s for n, s in pairs]. Исправление — решить, что вы хотели получить, и записать это явно: чаще всего обернуть значения в скобки, [(n, s) for n, s in pairs], и получить список кортежей.

Подсказка появилась в Python 3.10, который вышел в октябре 2021 года, вместе с большой волной более понятных сообщений об ошибках. В Python 3.9 тот же код дает просто invalid syntax. Ниже — разбор ошибки на одном примере, четыре варианта исправления под разные цели, случаи, где подсказки нет, и что еще нового появилось в подсказках с 2021 года по Python 3.14. Все выводы получены прогоном на Python 3.9.6, 3.10.21, 3.11.16, 3.12.14, 3.13.15 и 3.14.7.

Три термина из сообщения

  • Включение (comprehension) — выражение вида [выражение for переменные in источник]. Бывает списковым [...], множественным {...}, словарным {ключ: значение ...} и генераторным (...).
  • Цель включения (comprehension target) — в тексте ошибки так названо выражение ПЕРЕД for, то есть то, что попадет в результат. В примере [n, s for n, s in pairs] это n, s слева.
  • Переменные цикла — n, s ПОСЛЕ for. Их скобки не нужны: for n, s in pairs распаковывает каждую пару и работает всегда.

Итог: скобки просят поставить слева от for, а не справа. Слово target здесь не про переменные цикла, хотя в грамматике Python target обычно означает именно их.

Как ошибка выглядит

Минимальный файл, который падает:

pairs = [(1, "a"), (2, "b")]
result = [n, s for n, s in pairs]
print(result)

Вывод Python 3.14.7 (путь к файлу у вас будет свой):

  File "/w/bad.py", line 2
    result = [n, s for n, s in pairs]
              ^^^^
SyntaxError: did you forget parentheses around the comprehension target?

Программа не запускается вообще: это ошибка разбора, до выполнения первой строки дело не доходит. Поэтому print на третьей строке ничего не напечатает, а try/except вокруг такого кода ее не поймает. Галочки ^^^^ подчеркивают как раз n, s — выражение, которое нужно заключить в скобки.

Почему без скобок нельзя: запятая внутри [...] означает перечисление элементов списка. Парсер видит [n, s ... как литерал списка из двух элементов, а потом встречает for, которому здесь не место. Скобки (n, s) делают из двух значений один элемент — кортеж.

Как исправить: сначала решите, что хотели получить

Скобки — самое частое исправление, но не единственное. Одна и та же ошибка возникает, когда автор хотел четыре разные вещи. Рабочий файл со всеми вариантами:

pairs = [(1, "a"), (2, "b")]

tuples = [(n, s) for n, s in pairs]           # список кортежей
flat = [x for pair in pairs for x in pair]    # плоский список
numbers, letters = zip(*pairs)                # два отдельных набора
as_dict = {n: s for n, s in pairs}            # словарь

print(tuples)
print(flat)
print(numbers, letters)
print(as_dict)

Вывод одинаковый на Python 3.9.6 и 3.14.7:

[(1, 'a'), (2, 'b')]
[1, 'a', 2, 'b']
(1, 2) ('a', 'b')
{1: 'a', 2: 'b'}
Что нужно Как записать Результат
список пар [(n, s) for n, s in pairs] [(1, 'a'), (2, 'b')]
все значения подряд [x for pair in pairs for x in pair] [1, 'a', 2, 'b']
отдельно числа и буквы numbers, letters = zip(*pairs) два кортежа
словарь ключ -> значение {n: s for n, s in pairs} {1: 'a', 2: 'b'}

Отдельный частый случай — фигурные скобки. Код d = {n, s for n, s in pairs} дает ту же ошибку, но скобки тут обычно не то, что нужно. {(n, s) for ...} соберет множество кортежей, а если хотели словарь, нужна пара через двоеточие {n: s for ...}. Критерий простой: нужен доступ по ключу — словарь, нужна уникальность пар без порядка — множество.

Где подсказки нет

Подсказка срабатывает только для [...] и {...}. В похожих конструкциях сообщение другое, и его легко не узнать. Проверено на Python 3.14.7:

Код Сообщение Исправление
(n, s for n, s in pairs) invalid syntax ((n, s) for n, s in pairs)
dict(n, s for n, s in pairs) Generator expression must be parenthesized dict((n, s) for n, s in pairs)
{k: v, for k, v in pairs} invalid syntax убрать запятую: {k: v for k, v in pairs}

Первая строка важна: у генераторного выражения в круглых скобках подсказки про comprehension target нет даже в 3.14, только общее invalid syntax с галочками под for. Правило исправления то же — скобки вокруг выражения слева.

Во второй строке ошибка про другое: генератор передан в функцию вместе с еще одним аргументом без собственных скобок. Это сообщение было и в 3.9.

Одна и та же ошибка в Python 3.9 и 3.10+

Если код из примера у вас выдает не эту подсказку, а invalid syntax, проверьте версию:

python3 --version

На Python 3.9.6 тот же bad.py дает:

  File "bad.py", line 2
    result = [n, s for n, s in pairs]
                   ^
SyntaxError: invalid syntax

Галочка стоит под for, а не под выражением, и подсказки нет. Причина в парсере: в Python 3.9 появился новый PEG-парсер, а в 3.10 разработчики добавили в его грамматику специальные правила для типичных ошибок. Одно из них и ловит запятую перед for во включении.

Python 3.9 уже вне поддержки (конец 31 октября 2025 года). Сама 3.10 до октября 2026 года получает только исправления безопасности, после этого поддержка тоже заканчивается. Для новых проектов разумно брать актуальную ветку: на сентябрь 2026 года это 3.14, выход 3.15 по графику релизов запланирован на октябрь 2026 года.

Что нового в подсказках ошибок с 2021 года

Python 3.10 открыл серию улучшений, и в каждом следующем релизе сообщения становились точнее. Все строки таблицы — фактический вывод на указанных версиях; на более ранних тот же код дает сообщение без подсказки.

Версия Код с ошибкой Что пишет Python
3.10 [n, s for n, s in pairs] did you forget parentheses around the comprehension target?
3.10 незакрытая { в начале словаря '{' was never closed на строке со скобкой
3.10 if x > 1 без двоеточия expected ':'
3.10 if x = 1: Maybe you meant '==' or ':=' instead of '='?
3.10 items = [1, 2 3] Perhaps you forgot a comma?
3.10 нет отступа в теле if x: expected an indented block after 'if' statement on line 2
3.10 print(numbrs) NameError ... Did you mean: 'numbers'?
3.10 collections.namedtupel AttributeError ... Did you mean: 'namedtuple'?
3.11 любая ошибка во время выполнения галочки ^^^ под точным местом в строке трейсбека
3.12 print(sys.argv) без импорта Did you forget to import 'sys'?
3.13 любая ошибка в терминале цветной трейсбек, отключается PYTHON_COLORS=0
3.14 whille True: invalid syntax. Did you mean 'while'?

Две оговорки. Первая: подсказки Did you mean для имен и атрибутов — эвристика по похожести написания, а не анализ смысла; она может промолчать или предложить не то. Вторая: подсказка про опечатку в ключевом слове в 3.14 добавляется при выводе трейсбека. Если перехватить SyntaxError из compile() и прочитать e.msg, там будет просто invalid syntax.

Сообщения на других примерах синтаксических ошибок, включая незакрытые скобки и присваивание вместо сравнения, подробно разобраны в статье SyntaxError: invalid syntax в Python: причины и как исправить.

Что еще появилось в Python 3.10 (релиз 2021 года)

Кроме подсказок, 3.10 принес несколько изменений синтаксиса, которые сейчас встречаются в любом свежем коде. Если такой код падает у вас с invalid syntax, скорее всего, версия интерпретатора ниже 3.10. Файл, который проходит на 3.10.21 и 3.14.7:

from contextlib import nullcontext


def describe(point: tuple[int, int] | None) -> str:
    match point:
        case None:
            return "нет точки"
        case (0, 0):
            return "начало координат"
        case (x, 0):
            return f"на оси X, x={x}"
        case (x, y):
            return f"x={x}, y={y}"
    return "не точка"


with (
    nullcontext("a") as first,
    nullcontext("b") as second,
):
    print(first, second)

for p in [None, (0, 0), (3, 0), (1, 2)]:
    print(describe(p))

try:
    list(zip([1, 2, 3], ["a", "b"], strict=True))
except ValueError as err:
    print("ValueError:", err)

Вывод:

a b
нет точки
начало координат
на оси X, x=3
x=1, y=2
ValueError: zip() argument 2 is shorter than argument 1

Что здесь из 3.10:

  • match/case — сопоставление с образцом (PEP 634): case (x, 0) проверяет, что это пара со вторым нулем, и достает первый элемент в x.
  • int | None в аннотациях вместо Optional[int] и Union (PEP 604), без импорта из typing.
  • Несколько контекстных менеджеров в with в круглых скобках, по одному на строку.
  • zip(..., strict=True) (PEP 618): вместо молчаливого обрезания до короткого списка — ValueError.

На Python 3.9.6 этот файл падает уже на строке с match с SyntaxError: invalid syntax.

Если ошибка не уходит

  • Поставили скобки, ошибка та же. Скобки стоят справа от for, у переменных цикла. Перенесите их влево: [(n, s) for n, s in pairs].
  • Ошибка пропала, но результат не тот. Вы получили список кортежей, а нужен был плоский список или словарь — сверьтесь с таблицей вариантов выше.
  • Вместо подсказки invalid syntax. Либо Python 3.9 или более ранний (python3 --version), либо включение в круглых скобках, где подсказки нет.
  • Generator expression must be parenthesized. Генератор передан в функцию вместе с другим аргументом: оберните его в отдельные скобки.

Выводы

  • Сообщение did you forget parentheses around the comprehension target? появилось в Python 3.10 (октябрь 2021) и указывает на запятую в выражении слева от for внутри [...] или {...}.
  • Скобки нужны вокруг выражения-результата, а не вокруг переменных цикла: [(n, s) for n, s in pairs].
  • Перед исправлением решите, что хотели получить: список пар, плоский список, два набора через zip(*pairs) или словарь {n: s ...}.
  • В генераторе (...) подсказки нет даже в 3.14, там будет только invalid syntax; в Python 3.9 — тоже.
  • С 2021 года подсказки улучшались в каждом релизе: 3.10 — синтаксис и Did you mean, 3.11 — точные галочки в трейсбеке, 3.12 — забытый импорт, 3.13 — цвет, 3.14 — опечатки в ключевых словах.

Где применяется / связь с практикой

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

Включения — один из самых частых приемов в рабочем Python: из них собирают выборки данных, словари настроек, списки для отчетов. Умение по одной строке трейсбека понять, что сломалось, экономит больше времени, чем знание любой отдельной функции. Если хотите систематически пройти синтаксис, коллекции и работу с ошибками на практических задачах с разбором кода, посмотрите программу курса «Python-разработчик. Базовый уровень». Разобрать отдельные темы с преподавателями вживую можно на открытых уроках Otus.

FAQ

Можно ли поймать эту ошибку через try/except?
Не в том же файле: SyntaxError возникает при разборе, до выполнения. Поймать его можно только снаружи, например при compile(), exec() или импорте модуля с ошибкой.

Нужны ли скобки вокруг одного значения, например [n for n, s in pairs]?
Нет. Подсказка срабатывает только когда перед for несколько значений через запятую; одно выражение или уже готовый кортеж в скобках работают.

Почему подсказка на английском и можно ли ее перевести?
Тексты ошибок CPython встроены в интерпретатор и не локализуются. Ориентируйтесь на ключевую фразу и место, которое подчеркнуто галочками.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)