Python: TypeError 'NoneType object is not subscriptable' — как исправить ошибку
-
Ошибка TypeError: ‘NoneType’ object is not subscriptable — одна из самых частых в Python. Она возникает, когда код пытается обратиться к элементу объекта, который на самом деле равен
None. Это ломает работу с базами данных, API и функциями, возвращающими пустой результат.Понимание причины поможет быстро находить и фиксить такие баги. В этой статье разберём, почему
Noneне поддерживает индексацию, покажем реальные примеры и способы исправления. Вы научитесь проверять данные перед использованием и избегать подобных ошибок в проектах.Почему возникает ошибка ‘NoneType object is not subscriptable’
NoneType— это специальный тип в Python, который представляет отсутствие значения. ОбъектNoneне имеет методов__getitem__, поэтому попыткаnone_objectилиnone_object['key']вызывает TypeError. Ошибка сигнализирует: вы ожидаете список, словарь или строку, а получилиNone.Типичные сценарии — запросы к MongoDB, SQLite, API через
requestsили функции, которые не нашли данные. Методfind_one()в PyMongo возвращаетNone, если документ не существует. Аналогичноfetchone()в sqlite3 илиget()в JSON-ответах. Без проверки код падает на строке с квадратными скобками.Примеры возникновения ошибки
Вот классический кейс с базой данных:
def home(request): client = pymongo.MongoClient(settings.MONGO_SERVER) main_db = client[settings.MONGO_DATABASE] get_main_config = main_db.configurations.find_one({"name": "main_config"}) return render(request, 'dashboard/home.html', {"data": get_main_config["homepage_urls"]})Здесь
find_one()вернулNone, иget_main_config["homepage_urls"]вызывает ошибку. То же самое сrequests.get().json()— если API не нашёл данные,response['data']упадёт.- Базы данных:
cursor.fetchone()возвращаетNoneпри отсутствии записи. - API-запросы:
res.json().get('data')['list']ломается, если ключ отсутствует. - Функции:
get_user(123)возвращаетNone, но код пытаетсяuser['name'].
Основные способы исправления ошибки
Первый шаг — всегда проверяйте объект на
Noneперед индексацией. Используйтеif obj is not Noneили операторor. Это базовое правило для стабильного кода. Дополнительно логируйте значения переменных:print(f'{obj=}', type(obj))поможет отладить.Второй подход — используйте безопасные методы:
.get()для словарей с значением по умолчанию,or {}для пустых структур. Для списков подойдётobj if obj else None. Эти приёмы предотвращают краш и делают код чище.Шаги по исправлению
- Проверьте тип переменной:
print(type(get_main_config))покажетNoneType. - Добавьте условие:
if get_main_config: data = get_main_config.get('homepage_urls', []). - Обработайте None: Верните дефолтное значение или пустой шаблон.
- Протестируйте отсутствие данных: Создайте сценарий без записи в БД.
Сравнение методов проверки на None
Метод Пример кода Преимущества Недостатки if obj is not Noneif user: print(user['name'])Явная проверка, читаемо Требует if-блока obj or defaultdata = config or {}Коротко, inline Не работает с falsy-значениями (0, ‘’) .get()с defaultconfig.get('key', [])Безопасно для словарей Только для dict try-excepttry: data = obj except TypeError: data = []Ловит все ошибки Маскирует другие проблемы Выбирайте
if obj:для большинства случаев — это стандарт Python. Помните:if obj:проверяет не толькоNone, но и пустые коллекции.Правильные примеры фиксов
# Плохо get_main_config = main_db.configurations.find_one({"name": "main_config"}) data = get_main_config["homepage_urls"] # Хорошо get_main_config = main_db.configurations.find_one({"name": "main_config"}) if get_main_config: data = get_main_config.get("homepage_urls", []) else: data = []Для SQLite:
result = cursor.execute('SELECT cash FROM users WHERE id = ?', (user_id,)).fetchone() cash = result if result else 0Лучшие практики предотвращения ошибки
Пишите функции, которые гарантируют тип возвращаемого значения. Вместо
return find_one()возвращайтеfind_one() or {}. Используйте type hints:def get_config() -> dict | None. Это поможет IDE и mypy ловить баги на этапе разработки.Интегрируйте логирование:
logger.warning(f'Config not found: {query}'). Тестируйте edge-кейсы — отсутствие данных, сетевые сбои. Для API добавляйтеresponse.raise_for_status()перед парсингом JSON.- Type hints:
data: list[str] | None = None. - Дефолты: Всегда указывайте
get(key, default). - Валидация:
assert isinstance(obj, dict), f'Expected dict, got {type(obj)}'в тестах.
В продакшене избегайте
print()— используйтеloggingмодуль.Когда None — это не проблема, а фича
Иногда
Noneполезен для сигнала ‘не найдено’. Главное — обрабатывайте его предсказуемо. Подумайте о Optional-типах изtypingи union-типах в новых версиях Python. Стоит поэкспериментировать сmatch-выражениями в 3.10+ для элегантной обработки None и других случаев.Разные библиотеки по-разному возвращают отсутствие данных: Pandas —
NaN, SQLAlchemy —None. Изучите документацию PyMongo, sqlite3 и requests для нюансов. Это сэкономит часы дебага в сложных проектах. - Базы данных:
© 2024 - 2025 ExLends, Inc. Все права защищены.