Слоты - это то, что вам нужно:
Питонический способ - использовать слоты вместо игры с __setter__
. Хотя это может решить проблему, но не дает никакого улучшения производительности. Атрибуты объектов хранятся в словаре " __dict__
", по этой причине вы можете динамически добавлять атрибуты к объектам классов, которые мы создали до сих пор. Использование словаря для хранения атрибутов очень удобно, но это может означать пустую трату места для объектов, которые имеют лишь небольшое количество переменных экземпляра.
Слоты - хороший способ обойти эту проблему с расходом места. Вместо динамического дикта, который позволяет динамически добавлять атрибуты к объектам, слоты предоставляют статическую структуру, которая запрещает добавления после создания экземпляра.
Когда мы проектируем класс, мы можем использовать слоты, чтобы предотвратить динамическое создание атрибутов. Чтобы определить слоты, вы должны определить список с именем __slots__
. Список должен содержать все атрибуты, которые вы хотите использовать. Мы продемонстрируем это в следующем классе, в котором список слотов содержит только имя для атрибута «val».
class S(object):
__slots__ = ['val']
def __init__(self, v):
self.val = v
x = S(42)
print(x.val)
x.new = "not possible"
=> Не удается создать атрибут «новый»:
42
Traceback (most recent call last):
File "slots_ex.py", line 12, in <module>
x.new = "not possible"
AttributeError: 'S' object has no attribute 'new'
NB:
- Начиная с Python 3.3, преимущество оптимизации использования пространства уже не так впечатляюще. В Python 3.3 словари совместного использования ключей используются для хранения объектов. Атрибуты экземпляров могут совместно использовать часть своего внутреннего хранилища между собой, то есть часть, в которой хранятся ключи и их соответствующие хэши. Это помогает снизить потребление памяти программами, которые создают множество экземпляров не встроенных типов. Но все же это способ избежать динамически создаваемых атрибутов.
- Использование слотов также требует собственных затрат. Это нарушит сериализацию (например, рассол). Это также нарушит множественное наследование. Класс не может наследовать более чем от одного класса, который либо определяет слоты, либо имеет макет экземпляра, определенный в коде C (например, list, tuple или int).
__setattr__
но это, вероятно, было бы взломано.