Pour prendre en charge l'attribution arbitraire d'attributs, un objet a besoin d'un __dict__
: un dict associé à l'objet, où des attributs arbitraires peuvent être stockés. Sinon, il n'y a nulle part où mettre de nouveaux attributs.
Une instance de object
ne transporte pas un __dict__
- si c'était le cas, avant l'horrible problème de dépendance circulaire (puisque dict
, comme presque tout le reste, hérite de object
;-), cela mettrait en selle chaque objet en Python avec un dict, ce qui signifierait une surcharge de nombreux octets par objet qui n'a actuellement pas ou n'a pas besoin d'un dict (essentiellement, tous les objets qui n'ont pas d'attributs assignables arbitrairement n'ont pas ou n'ont pas besoin d'un dict).
Par exemple, en utilisant l'excellent pympler
projet (vous pouvez l'obtenir via svn à partir d' ici ), nous pouvons faire quelques mesures ...:
>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16
Vous ne voudriez pas que chacun int
prenne 144 octets au lieu de seulement 16, non? -)
Maintenant, quand vous créez une classe (héritant de quoi que ce soit), les choses changent ...:
>>> class dint(int): pass
...
>>> asizeof.asizeof(dint(23))
184
... le __dict__
est maintenant ajouté (en plus, un peu plus de frais généraux) - une dint
instance peut donc avoir des attributs arbitraires, mais vous payez un coût d'espace assez élevé pour cette flexibilité.
Et si vous vouliez des int
s avec un seul attribut supplémentaire foobar
...? C'est un besoin rare, mais Python offre un mécanisme spécial à cet effet ...
>>> class fint(int):
... __slots__ = 'foobar',
... def __init__(self, x): self.foobar=x+100
...
>>> asizeof.asizeof(fint(23))
80
...ne pas tout à fait aussi petit comme int
vous l' esprit! (ou même les deux int
s, un le self
et un le self.foobar
- le second peut être réaffecté), mais sûrement beaucoup mieux qu'un dint
.
Lorsque la classe a le __slots__
attribut spécial (une séquence de chaînes), alors l' class
instruction (plus précisément, la métaclasse par défaut, type
) n'équipe pas chaque instance de cette classe avec un __dict__
(et donc la possibilité d'avoir des attributs arbitraires), juste un fini , ensemble rigide de "slots" (essentiellement des endroits qui peuvent chacun contenir une référence à un objet) avec les noms donnés.
En échange de la flexibilité perdue, vous gagnez beaucoup d'octets par instance (probablement significatif uniquement si vous avez des millions d'instances qui circulent, mais il existe des cas d'utilisation pour cela).
object
type est immuable et de nouveaux attributs ne peuvent pas être ajoutés? Cela semble être le plus logique.