__slots__ в классе и при наследовании
class AbstractA(ABC):
__slots__ = ()
class AbstractB(ABC):
__slots__ = ()
class BaseA(AbstractA):
__slots__ = ('a',)
class BaseB(AbstractB):
__slots__ = ('b',)
class Child(AbstractA, AbstractB):
__slots__ = ('a', 'b')
c = Child()
1234567891011121314151617То есть мы вместо того, чтобы наследоваться от классов с конкретной реализацией (BaseA, BaseB), наследуемся от абстрактных классов
Однако __slots__ может вызвать проблемы при множественном наследовании.
Создание дочернего класса от родителей с обоими непустыми слотами не удается:
Если вы столкнетесь с этой проблемой, вы можете просто удалить __slots__ у родителей или, если вы контролируете родителей, дать им пустые слоты или выполнить рефакторинг для абстракций:
Добавьте '__dict__' к __slots__ чтобы получить динамическое назначение:
и сейчас
Таким образом, с '__dict__' в слотах мы теряем некоторые преимущества размера с преимуществом наличия динамического назначения и по-прежнему наличия слотов для имен, которые мы ожидаем
Когда вы наследуете объект, который не имеет слотов, вы получаете такую же семантику, когда используете __slots__ - имена, которые находятся в __slots__, указывают на значения, размещенные в слотах, тогда как любые другие значения помещаются в __dict__ экземпляра.
Избегать __slots__, потому что вы хотите иметь возможность добавлять атрибуты на лету, на самом деле не является хорошей причиной - просто добавьте '__dict__' в свой __slots__, если это необходимо.
Вы можете точно так же явно добавить __weakref__ в __slots__, если вам нужна эта функция.
Подводя итоги: если вы составляете миксины или используете абстрактные базовые классы, которые не предназначены для создания экземпляров, пустой __slots__ в этих родителях кажется лучшим способом гибкости для подклассов.
Чтобы продемонстрировать, сначала давайте создадим код с классом, который мы хотели бы использовать при множественном наследовании.
Мы могли бы использовать вышесказанное непосредственно путем наследования и объявления ожидаемых слотов:
Но нас это не волнует, это тривиальное одиночное наследование, нам нужен другой класс, от которого мы также могли бы унаследовать, возможно, с шумным атрибутом:
Теперь, если бы на обеих базах были непустые слоты, мы не смогли бы сделать следующее. (На самом деле, если бы мы хотели, мы могли бы дать AbstractBase непустые слоты a и b и исключить их из приведенного ниже объявления - оставлять их было бы неправильно):
И теперь у нас есть функциональность от обоих через множественное наследование, и мы все еще можем запретить создание экземпляров __dict__ и __weakref__:
Last updated
Was this helpful?