so it is immutable and you can get it via slicing.
>>> from collections import namedtuple
>>> Hat = namedtuple('Hat', ['style', 'size', 'color'])
>>> my_hat = Hat('safari', 'XL', 'Orange')
>>> my_hat
Hat(style='safari', size='XL', color='Orange')
>>> my_hat[0]
'safari'
>>> my_hat.color
'Orange'
>>> my_hat[1:]
('XL', 'Orange')
>>> style, size, color = my_hat
>>> size
'XL'
>>>
If thats all your using your classes for, then a named tuple is probably a better solution, or a dataclass. Though I normally just use dicts in that situation. If I see someone create a class without any methods, or atleast planned methods, I don't let it through code review.EDIT: Also, Raymond Hettinger created named tuples. I'm not normally one for call to authority, or hero worship, but I am a huge fan of his. I recommend that anyone interested in Python should watch as many of his talks as they can.
EDIT2: As masklinn pointed out, another really good use of named tuples is when you're already returning a tuple, and you realize it would be better if it had names. You could change it to a named tuple without breaking any of the existing code. Unless they're doing something dumb like halfassing type checking at runtime. (this use case is in the article, which i didn't read at first)
* extends tuples, so a namedtuple is literally a tuple (which is useful)
* sets up a bunch of properties for the "named fields", which are basically just names on the tuple elements
* sets up a few other utility methods e.g. nice formatting, `_make`, `_asdict`, `_replace`
Now the latter two are nice, and mostly replicated by dataclasses (or attrs). The first one is the raison d'être of namedtuples though: originally their purpose is to "upgrade" tuple return values into richer / clearer types e.g. urlparse originally returned a 6-utple which is not necessarily super wieldy / clear, you can probably infer that the 3rd element is the path but… after upgrading to namedtuple it's just `result.path which is usually much clearer.
And because namedtuples are still classes in and of themselves, you can inherit from them to create a class with a `__dict__` with relative ease.
The reason you reach for it is because it's tedious to write the same methods over and over to get things like a nice repr, methods covert between dicts, or pickling support.
The source from Python 3.6 is much more readable than 3.9 so I recommend reading that if you want to see how it works.
https://github.com/python/cpython/blob/3.6/Lib/collections/_...