Почему вы не можете добавлять атрибуты к объекту в python?

(написано в оболочке Python)

>>> o = object()
>>> o.test = 1

Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    o.test = 1
AttributeError: 'object' object has no attribute 'test'
>>> class test1:
    pass

>>> t = test1()
>>> t.test

Traceback (most recent call last):
  File "<pyshell#50>", line 1, in <module>
    t.test
AttributeError: test1 instance has no attribute 'test'
>>> t.test = 1
>>> t.test
1
>>> class test2(object):
    pass

>>> t = test2()
>>> t.test = 1
>>> t.test
1
>>> 

Почему объект не позволяет добавлять к нему атрибуты?

Ответ 1

Обратите внимание, что экземпляр object не имеет атрибута __dict__:

>>> dir(object())
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__']

Пример, иллюстрирующий это поведение в производном классе:

>>> class Foo(object):
...     __slots__ = {}
...
>>> f = Foo()
>>> f.bar = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'

Цитата из документов на slots:

[...] Объявление __slots__ принимает последовательность переменных экземпляра и резервирует достаточно места в каждом экземпляре для хранения значения для каждой переменной. Пространство сохраняется, поскольку __dict__ не создается для каждого экземпляра.

EDIT: Чтобы ответить ThomasH на комментарии, OP test class является классом "старого стиля". Попробуйте:

>>> class test: pass
...
>>> getattr(test(), '__dict__')
{}
>>> getattr(object(), '__dict__')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__dict__'

и вы заметите, что есть экземпляр __dict__. Класс объекта может не иметь значения __slots__, но результат тот же: отсутствие __dict__, что предотвращает динамическое присвоение атрибута. Я реорганизовал свой ответ, чтобы сделать это более ясным (переместите второй абзац вверх).

Ответ 2

Хороший вопрос, я предполагаю, что он связан с тем, что object является встроенным/расширением.

>>> class test(object):
...  pass
...
>>> test.test = 1
>>> object.test = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'object'

IIRC, это связано с наличием атрибута __dict__ или, вернее, setattr(), когда объект не имеет атрибута __dict__.