DJV DJV - 3 months ago 14
Python Question

Is print(defaultdict) supposed to be ugly?

Print

dict
and
defaultdict
:

>>> d = {'key': 'value'}
>>> print(d)
{'key': 'value'}

>>> dd = defaultdict(lambda: 'value')
>>> dd['key']
'value'
>>> print(dd)
defaultdict(<function <lambda> at 0x7fbd44cb6b70>, {'key': 'value'})


With nested structure it becomes ugly:

>>> nested_d = {'key1': {'key2': {'key3': 'value'}}}
>>> print(nested_d)
{'key1': {'key2': {'key3': 'value'}}}

>>> def factory():
... return defaultdict(factory)
...
>>> nested_dd = defaultdict(factory)
>>> nested_dd['key1']['key2']['key3'] = 'value'
>>> print(nested_dd)
defaultdict(<function factory at 0x7fbd44cd4ea0>, {'key1': defaultdict(<function factory at 0x7fbd44cd4ea0>, {'key2': defaultdict(<function factory at 0x7fbd44cd4ea0>, {'key3': 'value'})})})


Were there any reasons for not making it human-readable by default?

Answer

repr() output (defaultdict has no __str__, only __repr__) is debugging output. It is not meant to be pretty, it is meant to be functional. It tells you the type, the repr() of the callable that produces the default, and the contents.

From the __repr__ documentation:

This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.

Like all datatypes in Python, (except for strings for obvious reasons), no informal (__str__) is defined because it is up to the programmer to decide what output is suitable for their use-cases. No default can be set for that, because use-cases vary so widely. Output for a file has different needs than output to a GUI or to a web-page for example.

In Python 2, convert the object to a plain dictionary first, then use pprint() if you want 'pretty' output:

def todict(d):
    if not isinstance(d, dict):
        return d
    return {k: todict(v) for k, v in d.items()}

pprint(todict(nested_dd))

In Python 3, pprint supports defaultdict directly:

>>> pprint(nested_dd)
defaultdict(<function factory at 0x105ed2f28>,
            {'key1': defaultdict(<function factory at 0x105ed2f28>,
                                 {'key2': defaultdict(<function factory at 0x105ed2f28>,
                                                      {'key3': 'value'})})})
Comments