Wouldn't TypedDict come in handy here? This way we can kinda mimick a structural typing system. The only disadvantage I ran across here is that TypedDict can't handle recursive fields, unlike dataclasses. Otherwise, it seems to me like a more Pythonic choice, reminding of Clojure
I've written a lot of functionalish Python, and I've found that this is a consistent way to breed code that's hard to understand. Instead, I would default to (usually frozen) dataclasses to represent data—they're functional records that also let your code reflect the concepts that make sense for whatever you're doing. A list of dictionaries of strings looks like any other list of dictionaries of strings; a sequence of User objects has clear semantics and, as a benefit, is harder to mutate in unexpected ways.