:PROPERTIES: :ID: 05864d6a-7a05-4c11-af14-4faebfdd1926 :mtime: 20220527182207 :ctime: 20220527165926 :END: #+title: L'attribut de classe __slots__ * Introduction Par défaut, chaque objet possède l'attibut ~__dict__~ stockant la liste de ses attributs sous forme de ~dict~. Il est ainsi possible d'ajouter des attributs à un objet en dehors de la méthode ~__init__~ : #+BEGIN_SRC python :results output from sys import getsizeof class Dummy: def __init__(self, a: int, b: int) -> None: self.a = a self.b = b dummy = Dummy(1, 2) try: print(dummy.__slots__) except AttributeError as e: print(e) print(f'{dummy.__dict__=}') dummy.c = 3 print(f'{dummy.__dict__=}') print(f'{getsizeof(dummy) + getsizeof(dummy.__dict__)}') #+END_SRC #+RESULTS: : 'Dummy' object has no attribute '__slots__' : dummy.__dict__={'a': 1, 'b': 2} : dummy.__dict__={'a': 1, 'b': 2, 'c': 3} : 152 L'utilisation d'un ~dict~ pour stocker les attributs de chaque objet permet cette souplesse mais a pour conséquence un usage mémoire qui pourrait être amélioré. C'est pour cela que l'attributs ~__slots__~ a été ajouté par Python3. * Usage L'attribut de classe ~__slots__~ est un tuple (taille inférieure à celle d'un ~dict~ mais /imutable/) contenant les attributs des instances. #+BEGIN_SRC python :results output from sys import getsizeof class Dummy: __slots__ = ('a', 'b', 'c') def __init__(self, a: int, b: int) -> None: self.a = a self.b = b dummy = Dummy(1, 2) try: print(dummy.__dict__) except AttributeError as e: print(e) print(f'{dummy.__slots__=}') dummy.c = 3 print(f'{dummy.__slots__=}') try: dummy.d = 4 except AttributeError as e: print(e) print(f'{getsizeof(dummy) + getsizeof(dummy.__slots__)}') #+END_SRC #+RESULTS: : 'Dummy' object has no attribute '__dict__' : dummy.__slots__=('a', 'b', 'c') : dummy.__slots__=('a', 'b', 'c') : 'Dummy' object has no attribute 'd' : 120 ** Avantages L'usage de ~__slots__~ permet de réduire la taille des objets. Néanmoins, l'écart se réduit plus le nombre d'attributs augmente. Les ~__slots__~ sont donc utiles pour les classes ayant peu d'attributs et un grand nombre d'instances. Le principal avantage de ~__slots__~ réside dans les performances (environ 15% plus rapide), conséquence du temps d'accès plus rapide au contenu d'un ~tuple~ que d'un ~__dict__~. ** Inconvénients L'absence de ~__dict__~ empèche l'ajout dynamique d'attributs. L'usage de ~__slots__~ ajoute les règles suivantes quant à l'héritage : * Les slots d’une classe mère s’ajoutent à ceux de la classe fille, * Il ne peut exister qu’une seule classe mère avec une séquence de slots non vide, * Si une des classes membres de l'arbre d'héritage ne déclare pas de ~__slots__~, mêmes vides, les instances auront un attribut ~__dict__~ (perte de l'optimisation). * Références * [[https://www.invivoo.com/les-slots-une-optimisation-meconnue/][Les slots, une optimisation méconnue - Invivoo]]