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.
Отдельно проверьте методы, которые меняют объект на месте. Например, 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.
Такой порядок отделяет обычную опечатку от ошибки данных и от сбоя внутри вычисляемого атрибута. Главное доказательство — фактический объект в точке падения, а не предположение о том, что должно было лежать в переменной.