One straightforward way (which works with any class) is to define __slots__
:
In [1]: from dataclasses import dataclass
In [2]: @dataclass
...: class Foo:
...: __slots__ = 'bar','baz'
...: bar: int
...: baz: int
...:
In [3]: foo = Foo(42, 88)
In [4]: foo.biz = 10
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-d52b60444257> in <module>()
----> 1 foo.biz = 10
AttributeError: 'Foo' object has no attribute 'biz'
The purpose of slots is to serve as a small optimization. It allows the instances of the class to use a symbol table instead of a dict
as the namespace of the class. It increases the speed of attribute access slightly, and can significantly improve the per-instance memory usage (because the instance doesn't carry around a dict
underneath the hood), however, it disallows dynamic attribute setting.
This is actually my favorite feature of __slots__
.
Note, you must take care when using inheritance with slots, at least, if you want subclasses to retain the slots behavior.