web-dev-qa-db-fra.com

Pourquoi ne pouvez-vous pas ajouter d'attributs à un objet en python?

(Écrit en Python Shell)

>>> 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
>>> 

Pourquoi l'objet ne vous permet-il pas d'y ajouter des attributs?

60
quano

Notez qu'une instance object n'a pas __dict__ attribut:

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

Un exemple pour illustrer ce comportement dans une classe dérivée:

>>> 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'

Citant la documentation sur slots :

[...] Le __slots__ la déclaration prend une séquence de variables d'instance et réserve juste assez d'espace dans chaque instance pour contenir une valeur pour chaque variable. L'espace est économisé car __dict__ n'est pas créé pour chaque instance.

EDIT: Pour répondre à ThomasH à partir des commentaires, la classe de test OP est une classe "à l'ancienne". Essayer:

>>> 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__'

et vous remarquerez qu'il y a un __dict__ exemple. La classe d'objets peut ne pas avoir de __slots__ défini, mais le résultat est le même: absence de __dict__, ce qui empêche l'affectation dynamique d'un attribut. J'ai réorganisé ma réponse pour rendre cela plus clair (déplacer le deuxième paragraphe vers le haut).

45
ars

Bonne question, je suppose que cela a à voir avec le fait que object est un type intégré/extension.

>>> 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, cela a à voir avec la présence d'un attribut __dict__ Ou, plus correctement, setattr() explosant lorsque l'objet n'a pas d'attribut __dict__.

3
D.Shawley