__slots__ es un atributo especial de la clase que limita el conjunto de atributos permitidos en la instancia, ahorrando memoria y acelerando el acceso a los atributos. El uso de __slots__ es especialmente relevante para un gran número de objetos similares.
Historia de la cuestión:
La aparición de __slots__ está relacionada con el hecho de que, por defecto, cada instancia de un objeto Python tiene un diccionario de atributos (__dict__), lo que es conveniente pero costoso en términos de memoria. Para un millón de objetos con un conjunto pequeño de campos, surge una sobrecarga significativa.
Problema:
Las instancias de una clase normal pueden expandirse dinámicamente, lo que es conveniente, pero ineficiente. La aplicación de __slots__ limita la adición dinámica de nuevos atributos, elimina el diccionario de atributos de la instancia, ahorra memoria y acelera el acceso.
Solución:
Describa la lista de campos permitidos en el atributo __slots__:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # AttributeError: 'Point' object has no attribute 'z'
Características clave:
¿Se puede crear una instancia de una clase con slots y luego agregar un atributo que no está en la lista?
No. Al intentar agregar un atributo que no está en la lista de slots, se lanzará un AttributeError. Esto impone restricciones a la expandibilidad del objeto.
¿Se puede heredar de una clase con slots y agregar nuevos campos?
Sí, pero cada heredero debe declarar sus propios slots. En este caso, los slots parentales y actuales se combinan. Sin embargo, si no se declara slots en el heredero, ¡el descendiente nuevamente tendrá dict!
¿Funciona slots para tipos inmutables?
Sí, pero se deben implementar medidas adicionales para hacer que el objeto con slots sea inmutable (por ejemplo, mediante property sin setter).
Clase normal para un punto:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Ventajas:
Desventajas:
Clase similar, pero con slots:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
Ventajas:
Desventajas: