AttributeError: object has no attribute возникает, когда доступ к атрибуту или его присваивание не удались. В сообщении обычно есть фактический тип объекта и имя атрибута: 'list' object has no attribute 'items'. Но это не всегда означает, что такого имени нигде нет: property, дескриптор, __getattr__ или __getattribute__ могут сами выбросить AttributeError во время вычисления значения.
Поэтому сначала прочитай traceback целиком и найди выражение с упавшей точкой. Затем выдели объект слева от этой точки и проверь его runtime-тип. Примеры ниже проверены на CPython 3.14.5.
На каком объекте пропал атрибут
account.profile перед .email.Сначала найди точный объект и атрибут
В цепочке account.profile.email.lower() три обращения к атрибутам. Сообщение и последний кадр traceback показывают, на каком из них остановилось выполнение:
Traceback (most recent call last):
File "main.py", line 8, in <module>
print(account.profile.email.lower())
^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'email'
Здесь метод lower() ещё не вызывался. Атрибут profile найден, но его значение равно None; уже у этого значения код запросил email. Раздели цепочку и распечатай промежуточный объект:
class Account:
profile = None
account = Account()
profile = account.profile
print(repr(profile))
print(type(profile).__name__)
None
NoneType
Проверяй объект в том же запуске и как можно ближе к месту ошибки. Тип из аннотации, документации или окна отладчика не заменяет type(value) во время падения: в переменной уже могло оказаться другое значение.
Почему появляется NoneType object has no attribute
NoneType — тип единственного объекта None. Обычно функция ничего не нашла, одна из веток завершилась без return или метод изменил объект на месте и вернул None.
def find_user(users, user_id):
return users.get(user_id)
user = find_user({7: {"email": "dev@example.com"}}, 9)
print(user is None)
print(type(user).__name__)
True
NoneType
Исправление зависит от контракта функции. Если отсутствие пользователя нормально, обработай его до доступа к данным:
user = find_user(users, user_id)
if user is None:
return "пользователь не найден"
send_email(user["email"])
Если None невозможен по правилам программы, не маскируй его через getattr(user, "email", "") и не пытайся присвоить user.email вслепую. Найди ветку, которая вернула None, и исправь её. Для словаря нужен ключ user["email"], а не атрибут; разница между доступом к ключам и методами разобрана в статье про dict.
Если None вернула твоя собственная функция, механику return стоит один раз отработать руками: в бесплатном уроке «Калькулятор скидки: функции def и return» функцию пишут, вызывают и проверяют по шагам, регистрация не нужна. Остальные уроки Python идут в том же формате, с нуля.
Отдельно проверь методы, которые меняют объект на месте. Например, list.sort() возвращает None:
names = ["Вера", "Аня"]
result = names.sort()
print(names)
print(result)
['Аня', 'Вера']
None
После result = names.sort() вызов result.append(...) упадёт. Продолжать работу нужно с names, а если требуется новый список — использовать sorted(names).
Проверь опечатку и регистр
Имена атрибутов чувствительны к регистру. user.full_name, user.Full_Name и user.fullName — три разных имени. Сверь написание с местом объявления или документацией библиотеки, включая подчёркивания.
class User:
def __init__(self, full_name):
self.full_name = full_name
user = User("Анна Смирнова")
print(user.fullName)
AttributeError: 'User' object has no attribute 'fullName'. Did you mean: 'full_name'?
CPython иногда предлагает похожее имя, но подсказка эвристическая. Она не доказывает, что предложенный атрибут подходит по смыслу, и может отсутствовать в другом интерпретаторе или сообщении.
Убедись, что метод вызывается у того типа
Частая причина — имя метода верное, но объект не того типа. У словаря есть items(), у списка нет:
records = [{"id": 1}, {"id": 2}]
print(type(records).__name__)
print(records[0].items())
list
dict_items([('id', 1)])
Если вызвать records.items(), получится 'list' object has no attribute 'items'. Исправление зависит от данных: перебрать список словарей, выбрать один элемент либо изменить функцию, которая вернула список вместо ожидаемого словаря. Добавлять items самому списку не нужно.
То же относится к методам строк, списков и словарей: append() принадлежит списку, lower() — строке, get() — словарю. Проверяй не только наличие похожего метода, но и форму данных, которую должен обрабатывать этот участок программы.
Ветка init не создала атрибут экземпляра
Атрибут экземпляра может появиться лишь при выполнении определённой ветки. Тогда объекты одного класса будут устроены по-разному:
class Report:
def __init__(self, is_draft):
if is_draft:
self.title = "Черновик"
published = Report(False)
print(published.title)
AttributeError: 'Report' object has no attribute 'title'
Создай обязательный атрибут до ветвления, а внутри условия меняй его значение:
class Report:
def __init__(self, is_draft):
self.title = None
if is_draft:
self.title = "Черновик"
published = Report(False)
print(published.title)
None
Так у каждого Report одинаковый набор обязательных полей. Если None недопустим, конструктор должен получить заголовок или выбросить подходящее исключение сразу, а не создавать частично готовый объект.
Атрибут класса и атрибут экземпляра — не одно и то же
Имя в теле класса принадлежит классу. Присваивание через self обычно создаёт атрибут конкретного экземпляра:
class Session:
timeout = 30
def __init__(self, token):
self.token = token
session = Session("abc")
print(Session.timeout, session.timeout)
print(session.token)
30 30
abc
Session.token завершится с AttributeError: token появляется только после создания экземпляра. Обратный доступ обычно работает: если имени нет в экземпляре, Python продолжает поиск в классе и его базовых классах. Поэтому session.timeout находит классовое значение 30.
Не переноси token = None в тело класса только ради исчезновения ошибки. Это меняет модель данных и может особенно навредить с изменяемыми значениями: один классовый список будет общим для всех экземпляров. Для декларативных моделей используй предусмотренный ими способ объявления полей; базовый вариант с генерируемым __init__ показан в статье про dataclass.
Property и дескриптор могут сами выбросить AttributeError
Доступ profile.display_name может найти display_name в классе и вызвать его property, а ошибка возникнет уже внутри свойства:
class Profile:
@property
def display_name(self):
return self.raw_name.strip()
profile = Profile()
print(profile.display_name)
Traceback (most recent call last):
File "main.py", line 7, in <module>
print(profile.display_name)
^^^^^^^^^^^^^^^^^^^^
File "main.py", line 4, in display_name
return self.raw_name.strip()
^^^^^^^^^^^^^
AttributeError: 'Profile' object has no attribute 'raw_name'
Внешнее имя display_name существует. Не создана его зависимость raw_name. Это видно только по полному traceback: кадр свойства находится выше последней строки.
Дескрипторы, __getattribute__ и __getattr__ тоже выполняют пользовательский код во время доступа. Они могут вернуть вычисленное значение, создать атрибут динамически или поднять AttributeError. Поэтому формула «AttributeError всегда означает, что имени нет» неверна.
Проверь, какой модуль импортирован
Локальный файл может затенить модуль или сторонний пакет с тем же именем. Тогда импорт проходит, но у загруженного модуля нет ожидаемого атрибута:
import json
print(json.__name__)
print(getattr(json, "__file__", None))
print(json.dumps)
Если путь указывает на /project/json.py, а ты ожидаешь модуль стандартной библиотеки, переименуй локальный файл и перезапусти процесс. У некоторых встроенных или динамически созданных модулей __file__ может отсутствовать, поэтому диагностический getattr(..., None) здесь уместен.
Похожий случай, когда модуль не находится вообще, даёт другую ошибку. Проверка интерпретатора, sys.path и затенения разобрана в руководстве по ModuleNotFoundError.
Как использовать getattr, hasattr, dir и inspect.getattr_static
getattr(obj, name) нужен, когда имя атрибута хранится в строке. Третий аргумент задаёт запасное значение:
missing = object()
value = getattr("python", "casefold", missing)
print(value is missing)
print(callable(value))
False
True
Для отличия отсутствующего атрибута от настоящего None используй уникальный объект-сентинел, а не None. Но getattr выполняет обычный динамический поиск: он может вызвать property, дескриптор, __getattribute__ или __getattr__. Вариант с запасным значением способен скрыть AttributeError, возникший внутри такого кода.
hasattr(obj, name) делает тот же доступ и возвращает False, если он завершился именно AttributeError. Другие исключения функция не подавляет. Проверка может выполнить код свойства, изменить состояние, записать лог или сделать запрос, поэтому hasattr не гарантирует безопасную пассивную проверку.
dir(obj) полезен для быстрого поиска опечатки, но это подсказка, а не полный контракт объекта. Класс может переопределить __dir__; динамические атрибуты из __getattr__ иногда не попадают в список, а показанное имя всё равно может упасть при чтении.
Для отладки без вызова динамического доступа есть inspect.getattr_static():
import inspect
class Invoice:
@property
def total(self):
raise AttributeError("сумма ещё не рассчитана")
descriptor = inspect.getattr_static(Invoice(), "total")
print(type(descriptor).__name__)
property
getattr_static нашёл сам объект property, не выполняя его. У этого инструмента есть обратные ограничения: он может пропустить динамически создаваемый атрибут, вернуть дескриптор вместо значения и не увидеть поля экземпляра, если __dict__ затенён другим членом класса. Используй его для диагностики устройства объекта, а не как замену обычному доступу в рабочей логике.
Не лови AttributeError вокруг большой цепочки
Такой код маскирует слишком много разных дефектов:
try:
return account.profile.avatar.url
except AttributeError:
return None
Отсутствовать может profile, avatar или url; кроме того, AttributeError способен возникнуть внутри любого свойства. Обработчик сотрёт traceback и превратит баг в пустое значение.
Раздели цепочку, проверь ожидаемый необязательный результат явно и оставь неожиданные ошибки видимыми:
profile = account.profile
if profile is None:
return None
avatar = profile.avatar
if avatar is None:
return None
return avatar.url
Перехватывать AttributeError стоит только на узкой границе API, где отсутствие конкретного атрибута документировано как нормальный сценарий. Не используй голый except или except Exception ради продолжения работы. Правила выбора узкого обработчика собраны в статье про try/except.
Таблица диагностики AttributeError
| Сообщение или симптом | Что проверить | Что исправить |
|---|---|---|
'NoneType' object has no attribute 'email' | Значение объекта слева от .email, ветки return, методы с изменением на месте | Обработать допустимый None или исправить источник неожиданного None |
'list' object has no attribute 'items' | type(value), форму коллекции, элемент списка | Перебирать список, выбрать словарь или исправить возвращаемый тип |
| Имя отличается регистром или стилем | Объявление атрибута, документацию, dir(obj) как подсказку | Исправить точное написание, не создавать второе похожее имя |
| Ошибка только у части экземпляров | Все ветки __init__, фабрики и альтернативные конструкторы | Создавать обязательное поле на каждом пути инициализации |
Class.field падает, а instance.field работает | Где присваивается имя: в теле класса или через self | Обращаться через экземпляр либо объявить настоящее классовое значение |
| Имя видно в классе, но чтение падает | Полный traceback внутри property, __get__, __getattr__ | Исправить код или зависимость вычисляемого атрибута |
| У модуля нет ожидаемого метода | module.__name__, getattr(module, "__file__", None) | Убрать затеняющий файл или импортировать нужный модуль |
hasattr неожиданно возвращает False | Не выбрасывает ли свойство внутренний AttributeError | Проверить traceback прямого доступа и устройство через getattr_static |
Короткий порядок действий
- Прочитай последнюю строку и все кадры traceback, включая код внутри
property. - В упавшем выражении назови точный объект слева от точки и точное имя справа.
- Сохрани промежуточный объект и проверь
repr(value),type(value)иvalue is None. - Сверь регистр и убедись, что метод принадлежит фактическому типу.
- Для своего класса проверь все ветки
__init__, затем различи поля экземпляра и класса. - Для модуля распечатай
__file__; для динамического доступа учитывай выполнение дескрипторов. - Исправь источник неверного объекта или неполной инициализации, не скрывая ошибку широким
try/except.
Такой порядок отделяет обычную опечатку от ошибки данных и от сбоя внутри вычисляемого атрибута. Главное доказательство — фактический объект в точке падения, а не предположение о том, что должно было лежать в переменной.
Не нашёл свою ошибку в разборе? Вставь трейсбек в расшифровщик ошибок Python: он переведёт сообщение, назовёт причину и покажет починку.