How about explicitly declaring class attributes or reducing memory footprint of class variables. Slots seems to be an answer.
slots (__slots__) a special class variable that is assigned a sequence of strings that are variable names used by instance.
Example:
class Car:
__slots__ = ("brand_name", )
def __init__(self):
self.brand_name = "kia"
c = Car()
print(c.brand_name)
```
kia
```
The __slot__
declaration allows us to explicitly declare data members, which helps python to explicitly reserve space for them in memory and prevents the creation of __dict__
and __weakref__
attributes.
It also prevents the creation of any variables that aren’t declared in the __slots__
, doing so will result in AttributeError
c.price=1000
Traceback (most recent call last):
File "C:\Users\cosmi\PycharmProjects\python-mastery\my_solutions\test.py", line 32, in <module>
b.price = 1000
^^^^^^^
AttributeError: 'Car' object has no attribute 'price' and no __dict__ for setting new attributes
It also more efficient in terms of memory and speed.
Let’s compare the memory usage of a normal class and and __slot__
class.
class Car:
"""
Regular classes use a __dict__ for attributes
"""
def __init__(self):
self.brand_name = "hyundai"
class ECar:
__slots__ = ("brand_name", ) # this will prevent declaration of new slots
def __init__(self):
self.brand_name = "kia"
if __name__ == "__main__":
import tracemalloc
tracemalloc.start()
a = Car()
# a.price = 1000
print("current memory: {} \n peak memory: {}".format(*tracemalloc.get_traced_memory()))
tracemalloc.stop()
del a
tracemalloc.start(10)
b = ECar()
# b.price = 1000
print("current memory: {} \n peak memory: {}".format(*tracemalloc.get_traced_memory()))
current memory: 400
peak memory: 400
current memory: 112
peak memory: 112
As we can see it’s uses almost 4x less memory, my example is sort of insignificant from real life perspective, but hope you got the idea.
Conclusion: __slots__
are simple efficient and safe approach to python’s default attribute access.