Errors and violations¶
Slotscheck detects several different problems with slots.
Superclass has no slots¶
In order for memory savings from
__slots__ to work fully,
all base classes of a slotted classe need to define slots as well:
class NoSlots: pass class HasSlots: __slots__ = () class Bad(NoSlots): __slots__ = ('x', 'y') class Good(HasSlots): __slots__ = ('x', 'y')
You can see the memory impact of this mistake with
from pympler.asizeof import asizeof asizeof(Bad()) # 168 asizeof(Good()) # 48
In addition, if a superclass has no slots, all subclasses will get
which allows setting of arbitrary attributes.
Bad().foo = 5 # no error, even though `foo` is not a slot! Good().foo = 3 # raises AttributeError, as it should.
If a class defines a slot also present in a base class, the slot in the base class becomes inaccessible. This can cause surprising behavior. What’s worse: these inaccessible slots do take up space in memory!
class Base: __slots__ = ('x', ) class Bad(Base): __slots__ = ('x', 'z') class Good(Base): __slots__ = ('z', )
The official Python docs has this to say about overlapping slots (emphasis mine):
If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving its descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this.
Python doesn’t stop you from declaring the same slot multiple times. This mistake will cost you some memory:
class Good: __slots__ = ('a', 'b') class Bad: __slots__ = ('a', 'a', 'a', 'b', 'a', 'b') asizeof(Good()) # 48 asizeof(Bad()) # 80