Dataclasses are more of a replacement for NamedTuples, then dictionaries.
Whilst NamedTuples are designed to be immutable, dataclasses can offer that functionality by setting frozen=True in the decorator, but provide much more flexibility overall.
If you are into type hints in your Python code, they really come into play.
The other advantage is like you said - complex nested dictionaries. You can define Dataclasses as your types, and represent them within Dataclasses in a clear and concise way.
Consider the following:
@dataclass
class City:
code: str
population: int
@dataclass
class Country:
code: str
currency: str
cities: List[City]
@dataclass
class Locations:
countries: List[Country]
You can then write functions where you annotate the function param with dataclass name as a type hint and access it's attributes (similar to passing in a dictionary and accessing it's keys), or alternatively construct the dataclass and output it i.e.
def get_locations(....) -> Locations:
....
It makes the code very readable as opposed a large complicated dictionary.
You can also set defaults, which is not something that is allowed in NamedTuples but is allowed in dictionaries.
@dataclass
class Stock:
quantity: int = 0
You can also control whether you want the dataclass to be ordered etc in the decorator just like whether want it to be frozen, whereas normal dictionaries are not ordered. See here for more information
You get all the benefits of object comparison if you want them i.e. __eq__() etc. They also by default come with __init__ and __repr__ so you don't have to type out those methods manually like with normal classes.
There is also substantially more control over fields, allowing metadata etc.
And lastly you can convert it into a dictionary at the end by importing from dataclasses import dataclass asdict