__slots__ Python

Содержание
Введение
Пример
Разница в поведении
Проверка экономии памяти
Проверка скорости
__slots__ при наследовании
Далее по теме

Введение

Официальная документация: docs , wiki

Статья на сайте SQLAlchemy - Significant Improvements in Structural Memory Use

Пример

Без использования __slots__ у каждого экземпляра класса есть свой собственный словарь атрибутов

class Developer: def __init__(self, name, age, salary, framework): self.name = name self.age = age self.salary = salary self.framework = framework employee1 = Developer("Andrei", 36, 5000, "FastAPI") print(employee1.__dict__) print(hasattr(employee1, "__slots__"))

{'name': 'Andrei', 'age': 36, 'salary': 5000, 'framework': 'FastAPI'} False

При использовании __slots__ отдельные словари не создаются

class Developer: __slots__ = ("name", "age", "salary", "framework") def __init__(self, name, age, salary, framework): self.name = name self.age = age self.salary = salary self.framework = framework employee1 = Developer("Andrei", 36, 5000, "FastAPI") print(employee1.__dict__)

Traceback (most recent call last): File "C:\Users\Andrei\slots_demo.py", line 13, in <module> print(employee1.__dict__) AttributeError: 'Developer' object has no attribute '__dict__'

Можно обратиться к атрибуту __slots__

… print(employee1.__slots__) print(hasattr(employee1, "__slots__"))

('name', 'age', 'salary', 'framework') True

Разница в поведении

Попробуем добавить аттрибут к обычному классу

class Regular: def __init__(self, name, age): self.name = name self.age = age regular = Regular("Eugene", 59) regular.city = "Benalmadena" print(regular.city)

Benalmadena

Если тоже самое проделать с классом, где используются __slots__ появится AttributeError

class Slotted: __slots__ = ("name", "age") def __init__(self, name, age): self.name = name self.age = age slotted = Slotted("Andrei", 36) slotted.city = "Malaga" print(slotted.city)

Traceback (most recent call last): File "C:\Users\Andrei\slots_demo.py", line 10, in <module> slotted.city = "Malaga" ^^^^^^^^^^^^ AttributeError: 'Slotted' object has no attribute 'city'

Проверка экономии памяти

Если теперь в оба примера (без __slots__ и со __slots__) добавить проверку размера объекта метдом asizeof из pympler, окажется, что объект, где применялся __slots__ больше

from pympler import asizeof … print(f"asizeof() slotted size: {asizeof.asizeof(slotted_emp)}") … print(f"asizeof() not slotted size: {asizeof.asizeof(not_slotted_emp)}")

asizeof() slotted size: 240 asizeof() not slotted size: 560

Экономия приличная, но если воспользоваться другим измерителем размера, результат сильно исказится, подробнее в статье «Размер объекта в Python»

Проверка скорости

Выясним есть ли ускорение при обращении к атрибутам

import timeit from sys import getsizeof class Developer: __slots__ = ("name", "age", "salary", "framework") def __init__(self, name, age, salary, framework): self.name = name self.age = age self.salary = salary self.framework = framework class Programmer: def __init__(self, name, age, salary, framework): self.name = name self.age = age self.salary = salary self.framework = framework slotted_emp = Developer("Andrei", 36, 5000, "FastAPI") not_slotted_emp = Programmer("Eugene", 59, 95000, "Spring") # print(employee1.__dict__) # print(employee1.__slots__) def get_set_delete_fn(obj): def get_set_del(): obj.name = "foo" obj.name del obj.name obj.age = "foo" obj.age del obj.age obj.salary = "foo" obj.salary del obj.salary return get_set_del print(f"min slotted: {min(timeit.repeat(get_set_delete_fn(slotted_emp)))}") print(f"max slotted: {max(timeit.repeat(get_set_delete_fn(slotted_emp)))}") print(f"min not slotted: {min(timeit.repeat(get_set_delete_fn(not_slotted_emp)))}") print(f"max not slotted: {max(timeit.repeat(get_set_delete_fn(not_slotted_emp)))}")

min slotted: 0.10821229999999998 max slotted: 0.11044899999999991 min not slotted: 0.14354210000000012 max not slotted: 0.14311980000000002

Ускорение от __slotted__ в нашем примере очевидно.

__slots__ при наследовании

В родительском классе в __slots__ указываются его атрибуты. В производном классе в __slots__ нужно перечислять только новые для этого класса атрибуты. Перечислять заново родительские не нужно.

class Employee: __slots__ = ("name", "age", "salary") def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary def increase_salary(self, percent): self.salary += self.salary * (percent/100) class Developer(Employee): __slots__ = ("prog_language", "framework",) def __init__(self, name, age, salary, prog_language, framework): super().__init__(name, age, salary) self.prog_language = prog_language self.framework = framework class Tester(Employee): __slots__ = ("test_framework",) def __init__(self, name, age, salary, test_framework): super().__init__(name, age, salary) self.test_framework = test_framework def run_tests(self): print(f"Testing is started by {self.name}...") print("Tests are done.") employee1 = Developer("Andrei", 36, 5000, "python", "FastAPI") employee2 = Tester("Cem", 36, 5000, "PyTest") print(employee1.salary) employee1.increase_salary(10) print(employee1.salary) employee2.run_tests()

5000 5500.0 Testing is started by Cem... Tests are done.

Недостатки

При использовании __slots__ пропадает возможность динамически добавлять атрибуты. Можно пользоваться только тем, что определено в __slots__

При использовании множественного наследования __slots__ нужно указывать во всех родителях, хотя бы пустым.

Article author: Andrei Olegovich

Похожие статьи
ООП в Python
Классы
Методы
class variables
class methods
Статические методы
Наследование
Специальные методы
dataclass
__slots__
Декоратор property
super()

Search this site

Subscribe to Telegram channel @aofeed to follow new articles and updates to old ones

Go to channel

@aofeed

Ask a question in the Telegram group

@aofeedchat

Contacts and cooperation:
I recommend our hosting beget.ru
Write to info@urn.su, info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: