Если Python пишет TabError: inconsistent use of tabs and spaces in indentation, значит внутри одного блока отступы набраны и табами, и пробелами, и интерпретатор не может решить, на каком уровне вложенности стоит строка. Чинится это не переписыванием кода, а двумя действиями в редакторе: включить отрисовку невидимых символов и перевести весь файл на пробелы (в VS Code — команда Convert Indentation to Spaces, в PyCharm — Edit → Convert Indents → To Spaces).
Ниже — почему на экране всё выглядело ровно, чем TabError отличается от двух похожих IndentationError и как настроить редактор, чтобы ошибка не вернулась.
Что означает TabError: inconsistent use of tabs and spaces?
TabError — это отказ Python угадывать. Отступ задаёт вложенность, поэтому интерпретатор обязан точно знать, глубже ли текущая строка предыдущей. Если одна строка отступлена четырьмя пробелами, а следующая — табом, ответ зависит от того, чему равен таб: четырём пробелам или восьми. Гадать Python не станет и остановится ещё до запуска программы.
Вот функция расчёта цены со скидкой. Три строки отступлены пробелами, четвёртая — табом (пример сломан специально):
def sale_price(price):
if price > 1000:
return price * 0.9
return price
print(sale_price(1500))
File "C:\projects\sale.py", line 4
return price
TabError: inconsistent use of tabs and spaces in indentation
Две детали. Номер строки точный — Python указывает ровно ту строку, на которой отступы перестали сходиться. А вот подчёркивание проблемного места зависит от версии: вывод выше снят на Python 3.12, где под строкой нет ничего, а Python 3.13 и новее печатает под ней одинокий ^ в самом начале отступа. Информации это не добавляет — указывать по сути не на что, виноват невидимый символ.
Почему код выглядит ровно, но Python ругается на отступы?
Потому что таб — это не «символ шириной N», а команда «прыгни до следующей позиции табуляции». Если размер табуляции в редакторе равен четырём, таб занимает ровно столько же места, сколько четыре пробела, и строка встаёт в один столбец с соседними. Глазами разницы нет вообще, а для интерпретатора это два разных отступа. Именно поэтому в Python не видно, где ошибка в отступах: искать надо не глазами, а инструментами.
Метод expandtabs() показывает, во что превращается таб при ширине табуляции 4:
print(repr(" return price".expandtabs(4)))
print(repr(" return price".expandtabs(4)))
print(repr(" return price".expandtabs(4)))
' return price'
' return price'
' return price'
Третья строка — самая коварная. Четыре пробела плюс таб дают восемь колонок, ровно столько же, сколько два таба подряд. То есть строка, которая на экране выглядит отступленной «чуть сильнее соседей», на самом деле проваливается на два уровня вглубь.
Python ошибка отступов табы и пробелы: смотрим на строку через repr()
Самый быстрый способ увидеть правду о строке, ничего не настраивая, — функция repr(). Она печатает таб как \t, а пробелы оставляет пробелами:
print(repr(" return price"))
print(repr(" return price"))
' return price'
'\treturn price'
Тот же приём по всему файлу — детектор подозрительных строк:
source = "def sale_price(price):\n if price > 1000:\n return price * 0.9\n\treturn price\n"
for number, line in enumerate(source.splitlines(), start=1):
if "\t" in line:
print(number, repr(line))
4 '\treturn price'
В своём проекте подставь в source содержимое файла через open(...).read().
Как включить показ пробелов и табов в VS Code и PyCharm?
Это единственный шаг, который превращает невидимую проблему в видимую: редактор начинает рисовать пробел серой точкой, а таб — стрелкой. Строка с табом сразу отличается от соседних, и вы сами видите, какие строки надо переделать. Включается одним пунктом меню, без плагинов и перезапуска.
VS Code: показать пробелы и табы
Меню View → Appearance → Render Whitespace или настройка:
"editor.renderWhitespace": "all"
Пробелы станут точками ·, табы — стрелками →. Заодно посмотрите на строку состояния внизу справа: Spaces: 4 или Tab Size: 4 — это то, чем редактор отбивает отступ прямо сейчас.
PyCharm: Show Whitespaces
Меню View → Active Editor → Show Whitespaces. Полезно включить рядом и Show Indent Guides: вертикальные линии сразу покажут строку, которая выбилась из уровня.
Как заменить табы на пробелы в Python-файле целиком?
Руками это делать не нужно. И VS Code, и PyCharm переиндентируют весь файл одной командой: каждый ведущий таб становится нужным числом пробелов, структура блоков сохраняется, код внутри строк не трогается. Это и есть настоящее лечение, в отличие от правки той единственной строки, на которую указал Python.
| Инструмент |
Что сделать |
Что изменится |
| VS Code |
Ctrl+Shift+P → Convert Indentation to Spaces |
Все ведущие табы станут пробелами |
| PyCharm |
Edit → Convert Indents → To Spaces |
То же для файла или папки |
| macOS, Linux |
expand -t 4 sale.py > fixed.py |
Разворачивает все табы, не только ведущие |
| Любая ОС |
black sale.py |
Отступ становится 4 пробела — но только если файл разбирается |
Нюанс про expand: он разворачивает вообще все табы, включая настоящий символ табуляции внутри строки — например, в print("имя значение") изменятся ваши данные. Команды редакторов и black трогают только отступ.
И нюанс про black: файл, который уже падает с TabError, он отформатировать не может — сам останавливается с cannot use --safe with this file; failed to parse source file AST: inconsistent use of tabs and spaces in indentation. Так что сначала команда редактора или expand, и только потом black. Файл, где отступы набраны одними табами и ничего не перемешано, black переводит на пробелы без возражений.
Чем TabError отличается от IndentationError?
TabError — частный случай IndentationError, а тот, в свою очередь, частный случай SyntaxError. Все три появляются ещё до запуска программы, на этапе разбора файла, но говорят о разном: TabError — отступы перемешаны, expected an indented block — отступа нет там, где он обязан быть, unexpected indent — отступ есть там, где его быть не должно.
print(issubclass(TabError, IndentationError))
print(issubclass(IndentationError, SyntaxError))
True
True
Часто ищут отдельно «python indentationerror expected an indented block» и «python unexpected indent что делать». Вот дословная таблица, чтобы за секунду понять, какое из четырёх сообщений у вас на экране:
| Сообщение |
Что случилось |
Что делать |
TabError: inconsistent use of tabs and spaces in indentation |
В одном блоке отступ набран и табами, и пробелами |
Перевести файл на пробелы |
IndentationError: expected an indented block after 'if' statement on line 2 |
После строки с двоеточием тело блока не отступлено |
Добавить 4 пробела телу |
IndentationError: unexpected indent |
Отступ есть, а строки с двоеточием перед ним нет |
Убрать лишний отступ |
IndentationError: unindent does not match any outer indentation level |
Строка вышла из блока, но не совпала ни с одним внешним уровнем |
Выровнять по внешнему блоку |
Вторая строка таблицы вживую (после if нет тела):
price = 1500
if price > 1000:
print("скидка")
File "C:\projects\discount.py", line 3
print("скидка")
^^^^^
IndentationError: expected an indented block after 'if' statement on line 2
Начиная с Python 3.10 сообщение договаривает главное — after 'if' statement on line 2 прямо называет строку, тело которой вы забыли отступить. Третья строка таблицы выглядит зеркально:
price = 1500
print(price)
File "C:\projects\report.py", line 2
print(price)
IndentationError: unexpected indent
Где вообще нужны блоки с отступом, разложено в справочнике: условия if / elif / else и циклы for и while.
Откуда табы берутся в вашем файле
Python ошибка отступов табы и пробелы почти никогда не появляется на пустом месте. Источников четыре: копипаста из браузера, чужой код с GitHub из редактора с табами, автоопределение отступа в самом редакторе и Блокнот, где клавиша Tab вставляет настоящий символ табуляции.
Самый неприятный вариант — когда файл с перемешанными отступами не падает. Тут первая функция на пробелах, вторая на табе, и Python молчит:
def sale_price(price):
return price * 0.9
def delivery_price(weight):
return 300
print(sale_price(1000), delivery_price(2))
900.0 300
Ошибки нет, потому что Python сравнивает отступы только внутри одного блока, а это два разных блока. Файл проработает ровно до того дня, когда вы допишете в delivery_price вторую строку пробелами. Упадёт он тогда на новой строке, и виноватой будет выглядеть она, хотя таб лежал в файле с самого начала.
Сколько пробелов должно быть в отступе Python?
Четыре. Это прямая рекомендация PEP 8, официального руководства по стилю Python: один уровень вложенности — четыре пробела. Технически интерпретатор примет любое постоянное количество пробелов, хоть один, хоть семь, и даже табы, но четыре пробела — то, на что настроены все линтеры и автоформатеры и в каком виде вы будете читать любой чужой код. PEP 8 отдельно оговаривает: пробелы предпочтительнее табов, а смешивать их нельзя.
Быстрее всего это входит в руки на задачах с вложенными блоками. FizzBuzz — это цикл, внутри которого цепочка if / elif / else, то есть три уровня отступа сразу.
Настройки редактора, чтобы ошибка не вернулась
Проблема закрывается навсегда тремя параметрами. Для VS Code:
"editor.insertSpaces": true,
"editor.tabSize": 4,
"editor.detectIndentation": false
Третий важнее первых двух. Пока detectIndentation включён, VS Code смотрит на открытый файл, видит там таб и начинает вставлять табы, даже если вы просили пробелы. Именно так чистый проект заражается табами после одного чужого файла.
Для PyCharm: Settings → Editor → Code Style → Python, снять Use tab character, поставить Tab size и Indent равными 4, а на странице Code Style снять Detect and use existing file indents for editing.
Чтобы правило действовало у всех, положите в корень проекта .editorconfig (PyCharm понимает его сразу, VS Code — с расширением EditorConfig):
root = true
[*.py]
indent_style = space
indent_size = 4
Проверка из терминала: tabnanny вместо python -tt
Совет «запусти python -tt» кочует по форумам с эпохи Python 2, где -t предупреждал о неоднозначных отступах, а -tt превращал предупреждение в ошибку. В Python 3 этого нет: опция принимается молча, ничего не делает и даже не упоминается в python --help. Смысла в ней ноль — неоднозначное смешение и так стало ошибкой.
Рабочий инструмент лежит в стандартной библиотеке:
$ python -m tabnanny sale.py
sale.py 4 '\treturn price'
Формат: имя файла, номер строки и сама строка через repr(), где таб виден как \t. Каталог тоже можно: python -m tabnanny .. Две оговорки: tabnanny ищет неоднозначность, а не любые табы, поэтому файл с отступами только из табов пропустит молча, и код возврата у него нулевой даже при находках. Для CI берите flake8 (правила W191 и E101) или black.
Частые ошибки
- Чинить отступ клавишей Tab. Нажатие Tab добавляет в файл ещё один таб, то есть ту же самую проблему. Ставьте четыре пробела или сначала переключите редактор в режим пробелов.
- Править только ту строку, на которую указал Python. Он сообщает о первой строке, где отступы перестали сходиться, а не обо всех: почините одну — упадёт следующая. Переиндентируйте файл целиком.
- Доверять глазам. Пока показ невидимых символов выключен, таб и четыре пробела неотличимы. Сначала Render Whitespace, потом всё остальное.
- Считать, что молчание Python означает порядок. Табы и пробелы в разных блоках одного файла не вызывают ошибку сегодня, но вызовут её при первой же правке.
- Ставить
python -tt. В Python 3 эта опция не делает ничего. Нужен tabnanny, flake8 или black.
- Выравнивать отступ на глаз. Если строка выше начинается с таба, совпадение зависит от ширины табуляции, а не от числа пробелов.
- Не читать сообщение до конца.
expected an indented block after 'if' statement on line 2 называет две разные строки: проблемную и виновницу.
Если файл падает при двойном клике и консольное окно исчезает раньше, чем вы успели прочитать TabError, — это отдельная беда, разобранная в статье скрипт закрывается сразу после запуска. И табы не единственные невидимые символы, которые ломают файл: второй частый случай — кодировка, про неё есть разбор кракозябры при чтении файла.
Практика: почини отступы в браузере
Отступы усваиваются только руками. Возьмите задачу Сложи только чётные: цикл, внутри него условие, два уровня отступа — ровно та конструкция, на которой чаще всего ловят TabError. Решение проверяют скрытые тесты прямо в браузере, ставить Python не нужно.
Мини-резюме
TabError: inconsistent use of tabs and spaces in indentation означает, что в одном блоке отступ набран и табами, и пробелами.
- Баг невидим, потому что таб рисуется той же ширины, что и соседние пробелы. Сначала включите Render Whitespace в VS Code или Show Whitespaces в PyCharm.
- Лечение — одна команда на весь файл:
Convert Indentation to Spaces или Edit → Convert Indents → To Spaces, а не правка одной строки.
- Чтобы ошибка не вернулась:
insertSpaces = true, tabSize = 4, detectIndentation = false плюс .editorconfig в корне.
- TabError,
expected an indented block и unexpected indent — три разные ошибки: перемешано, отступа нет, отступ лишний.
python -tt в Python 3 не работает; проверяйте python -m tabnanny файл.py, flake8 или black. PEP 8: четыре пробела на уровень.
Если Python пишет
TabError: inconsistent use of tabs and spaces in indentation, значит внутри одного блока отступы набраны и табами, и пробелами, и интерпретатор не может решить, на каком уровне вложенности стоит строка. Чинится это не переписыванием кода, а двумя действиями в редакторе: включить отрисовку невидимых символов и перевести весь файл на пробелы (в VS Code — командаConvert Indentation to Spaces, в PyCharm — Edit → Convert Indents → To Spaces).Ниже — почему на экране всё выглядело ровно, чем TabError отличается от двух похожих IndentationError и как настроить редактор, чтобы ошибка не вернулась.
Что означает TabError: inconsistent use of tabs and spaces?
TabError — это отказ Python угадывать. Отступ задаёт вложенность, поэтому интерпретатор обязан точно знать, глубже ли текущая строка предыдущей. Если одна строка отступлена четырьмя пробелами, а следующая — табом, ответ зависит от того, чему равен таб: четырём пробелам или восьми. Гадать Python не станет и остановится ещё до запуска программы.
Вот функция расчёта цены со скидкой. Три строки отступлены пробелами, четвёртая — табом (пример сломан специально):
def sale_price(price): if price > 1000: return price * 0.9 return price print(sale_price(1500))Две детали. Номер строки точный — Python указывает ровно ту строку, на которой отступы перестали сходиться. А вот подчёркивание проблемного места зависит от версии: вывод выше снят на Python 3.12, где под строкой нет ничего, а Python 3.13 и новее печатает под ней одинокий
^в самом начале отступа. Информации это не добавляет — указывать по сути не на что, виноват невидимый символ.Почему код выглядит ровно, но Python ругается на отступы?
Потому что таб — это не «символ шириной N», а команда «прыгни до следующей позиции табуляции». Если размер табуляции в редакторе равен четырём, таб занимает ровно столько же места, сколько четыре пробела, и строка встаёт в один столбец с соседними. Глазами разницы нет вообще, а для интерпретатора это два разных отступа. Именно поэтому в Python не видно, где ошибка в отступах: искать надо не глазами, а инструментами.
Метод
expandtabs()показывает, во что превращается таб при ширине табуляции 4:print(repr(" return price".expandtabs(4))) print(repr(" return price".expandtabs(4))) print(repr(" return price".expandtabs(4)))Третья строка — самая коварная. Четыре пробела плюс таб дают восемь колонок, ровно столько же, сколько два таба подряд. То есть строка, которая на экране выглядит отступленной «чуть сильнее соседей», на самом деле проваливается на два уровня вглубь.
Python ошибка отступов табы и пробелы: смотрим на строку через repr()
Самый быстрый способ увидеть правду о строке, ничего не настраивая, — функция
repr(). Она печатает таб как\t, а пробелы оставляет пробелами:print(repr(" return price")) print(repr(" return price"))Тот же приём по всему файлу — детектор подозрительных строк:
source = "def sale_price(price):\n if price > 1000:\n return price * 0.9\n\treturn price\n" for number, line in enumerate(source.splitlines(), start=1): if "\t" in line: print(number, repr(line))В своём проекте подставь в
sourceсодержимое файла черезopen(...).read().Как включить показ пробелов и табов в VS Code и PyCharm?
Это единственный шаг, который превращает невидимую проблему в видимую: редактор начинает рисовать пробел серой точкой, а таб — стрелкой. Строка с табом сразу отличается от соседних, и вы сами видите, какие строки надо переделать. Включается одним пунктом меню, без плагинов и перезапуска.
VS Code: показать пробелы и табы
Меню View → Appearance → Render Whitespace или настройка:
Пробелы станут точками
·, табы — стрелками→. Заодно посмотрите на строку состояния внизу справа:Spaces: 4илиTab Size: 4— это то, чем редактор отбивает отступ прямо сейчас.PyCharm: Show Whitespaces
Меню View → Active Editor → Show Whitespaces. Полезно включить рядом и Show Indent Guides: вертикальные линии сразу покажут строку, которая выбилась из уровня.
Как заменить табы на пробелы в Python-файле целиком?
Руками это делать не нужно. И VS Code, и PyCharm переиндентируют весь файл одной командой: каждый ведущий таб становится нужным числом пробелов, структура блоков сохраняется, код внутри строк не трогается. Это и есть настоящее лечение, в отличие от правки той единственной строки, на которую указал Python.
Ctrl+Shift+P→Convert Indentation to Spacesexpand -t 4 sale.py > fixed.pyblack sale.pyНюанс про
expand: он разворачивает вообще все табы, включая настоящий символ табуляции внутри строки — например, вprint("имя значение")изменятся ваши данные. Команды редакторов иblackтрогают только отступ.И нюанс про
black: файл, который уже падает с TabError, он отформатировать не может — сам останавливается сcannot use --safe with this file; failed to parse source file AST: inconsistent use of tabs and spaces in indentation. Так что сначала команда редактора илиexpand, и только потомblack. Файл, где отступы набраны одними табами и ничего не перемешано,blackпереводит на пробелы без возражений.Чем TabError отличается от IndentationError?
TabError — частный случай IndentationError, а тот, в свою очередь, частный случай SyntaxError. Все три появляются ещё до запуска программы, на этапе разбора файла, но говорят о разном: TabError — отступы перемешаны,
expected an indented block— отступа нет там, где он обязан быть,unexpected indent— отступ есть там, где его быть не должно.print(issubclass(TabError, IndentationError)) print(issubclass(IndentationError, SyntaxError))Часто ищут отдельно «python indentationerror expected an indented block» и «python unexpected indent что делать». Вот дословная таблица, чтобы за секунду понять, какое из четырёх сообщений у вас на экране:
TabError: inconsistent use of tabs and spaces in indentationIndentationError: expected an indented block after 'if' statement on line 2IndentationError: unexpected indentIndentationError: unindent does not match any outer indentation levelВторая строка таблицы вживую (после
ifнет тела):price = 1500 if price > 1000: print("скидка")Начиная с Python 3.10 сообщение договаривает главное —
after 'if' statement on line 2прямо называет строку, тело которой вы забыли отступить. Третья строка таблицы выглядит зеркально:price = 1500 print(price)Где вообще нужны блоки с отступом, разложено в справочнике: условия if / elif / else и циклы for и while.
Откуда табы берутся в вашем файле
Python ошибка отступов табы и пробелы почти никогда не появляется на пустом месте. Источников четыре: копипаста из браузера, чужой код с GitHub из редактора с табами, автоопределение отступа в самом редакторе и Блокнот, где клавиша Tab вставляет настоящий символ табуляции.
Самый неприятный вариант — когда файл с перемешанными отступами не падает. Тут первая функция на пробелах, вторая на табе, и Python молчит:
def sale_price(price): return price * 0.9 def delivery_price(weight): return 300 print(sale_price(1000), delivery_price(2))Ошибки нет, потому что Python сравнивает отступы только внутри одного блока, а это два разных блока. Файл проработает ровно до того дня, когда вы допишете в
delivery_priceвторую строку пробелами. Упадёт он тогда на новой строке, и виноватой будет выглядеть она, хотя таб лежал в файле с самого начала.Сколько пробелов должно быть в отступе Python?
Четыре. Это прямая рекомендация PEP 8, официального руководства по стилю Python: один уровень вложенности — четыре пробела. Технически интерпретатор примет любое постоянное количество пробелов, хоть один, хоть семь, и даже табы, но четыре пробела — то, на что настроены все линтеры и автоформатеры и в каком виде вы будете читать любой чужой код. PEP 8 отдельно оговаривает: пробелы предпочтительнее табов, а смешивать их нельзя.
Быстрее всего это входит в руки на задачах с вложенными блоками. FizzBuzz — это цикл, внутри которого цепочка
if/elif/else, то есть три уровня отступа сразу.Настройки редактора, чтобы ошибка не вернулась
Проблема закрывается навсегда тремя параметрами. Для VS Code:
Третий важнее первых двух. Пока
detectIndentationвключён, VS Code смотрит на открытый файл, видит там таб и начинает вставлять табы, даже если вы просили пробелы. Именно так чистый проект заражается табами после одного чужого файла.Для PyCharm: Settings → Editor → Code Style → Python, снять Use tab character, поставить Tab size и Indent равными 4, а на странице Code Style снять Detect and use existing file indents for editing.
Чтобы правило действовало у всех, положите в корень проекта
.editorconfig(PyCharm понимает его сразу, VS Code — с расширением EditorConfig):Проверка из терминала: tabnanny вместо python -tt
Совет «запусти
python -tt» кочует по форумам с эпохи Python 2, где-tпредупреждал о неоднозначных отступах, а-ttпревращал предупреждение в ошибку. В Python 3 этого нет: опция принимается молча, ничего не делает и даже не упоминается вpython --help. Смысла в ней ноль — неоднозначное смешение и так стало ошибкой.Рабочий инструмент лежит в стандартной библиотеке:
Формат: имя файла, номер строки и сама строка через
repr(), где таб виден как\t. Каталог тоже можно:python -m tabnanny .. Две оговорки:tabnannyищет неоднозначность, а не любые табы, поэтому файл с отступами только из табов пропустит молча, и код возврата у него нулевой даже при находках. Для CI берите flake8 (правила W191 и E101) илиblack.Частые ошибки
python -tt. В Python 3 эта опция не делает ничего. Нуженtabnanny, flake8 илиblack.expected an indented block after 'if' statement on line 2называет две разные строки: проблемную и виновницу.Если файл падает при двойном клике и консольное окно исчезает раньше, чем вы успели прочитать TabError, — это отдельная беда, разобранная в статье скрипт закрывается сразу после запуска. И табы не единственные невидимые символы, которые ломают файл: второй частый случай — кодировка, про неё есть разбор кракозябры при чтении файла.
Практика: почини отступы в браузере
Отступы усваиваются только руками. Возьмите задачу Сложи только чётные: цикл, внутри него условие, два уровня отступа — ровно та конструкция, на которой чаще всего ловят TabError. Решение проверяют скрытые тесты прямо в браузере, ставить Python не нужно.
Мини-резюме
TabError: inconsistent use of tabs and spaces in indentationозначает, что в одном блоке отступ набран и табами, и пробелами.Convert Indentation to Spacesили Edit → Convert Indents → To Spaces, а не правка одной строки.insertSpaces= true,tabSize= 4,detectIndentation= false плюс.editorconfigв корне.expected an indented blockиunexpected indent— три разные ошибки: перемешано, отступа нет, отступ лишний.python -ttв Python 3 не работает; проверяйтеpython -m tabnanny файл.py, flake8 илиblack. PEP 8: четыре пробела на уровень.