Let me introduce: __slots__
For simple classes, you can also just use `NamedTuple` like:<p><pre><code>  from typing import NamedTuple
  class Foo(NamedTuple):
      bar: int = 0
      baz: str = &#x27;default&#x27;
  foo = Foo(1, baz=&#x27;not default&#x27;)
</code></pre>
This provides the same performance benefits, and is very similar in a lot of ways to a Scala case class -- aside from removing the boilerplate of stating each attribute twice in __init__ and again in __slots__, it also provides nice default implementations for __repr__, __str__ (something like `Foo(bar=1, baz=&#x27;quux&#x27;)`), __hash__, and __eq__ (using member equality rather than identity).<p>The downsides are A, you can&#x27;t inherit from any other class (it&#x27;s syntactically valid, but silently ignored (!) though it will be caught by linters), and B, `isinstance(foo, tuple)` returns `True`, which messes with a lot of reflection code (e.g. the `json` module will not serialize them like you expect)