Q:

Should complex return objects be wrapped in a helper class?

In refactoring some code I found a helper method get_records_from_file that has a complex return signature:
class RecordDefinition:

    def __init__(self):
        self.foo = None
        self.bar = None

def get_records_from_file(file_name) -> Dict[int, List[Dict[str, RecordDefinition]]]:
...

After some inspection I understand that this return type really means:
Dict[record_group_id, List[Dict[record_type_id, RecordDefinition]]]

In other projects (and other languages) I've seen this very thing change into:
Dict[record_group_id, List[RecordTypeCollection]]

Which leads to:
Dict[record_group_id, RecordCollection]

And finally ending in:
RecordGroupCollection

Generally, Is this kind of replacement desirable? More explicitly, should I change complex return objects like this to Object Oriented Classes? I see some benefit here that allows structures to be more explicitly named. But this adds a lot of code in the form of smaller classes.
In python, I get the impression that this kind of class creation is frowned upon. Is my assumption correct?

A:

I think PEP 20 can provide some guidance here.

Explicit is better than implicit.

Creating a wrapper class for this data structure has the benefit of making the code more explicit through naming the structure and its component fields.
This might be opinionated, but I think the following also apply to your example:

Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.

A class with methods and fields would be less "nested" than the raw data structure.
However...

[...] practicality beats purity.

I don't think it's safe to say as a hard-and-fast rule that you should always wrap nested structures.  A wrapper class could be overkill if it's wrapping a very simple structure (e.g., perhaps if the method were just returning a tuple of a list and another data type).  It's also arguable that if the class has no better business-domain name than Collection, it might be too abstract to add value.
The question to ask when evaluating whether to create a class in these situations is, do you think more developers will find it easier to work with the new class or the original data structure?
In the example you've provided, I think it's very reasonable (and in my opinion preferable) to create the new class.

