from typing import MutableMapping


def flatten(d, separator='_', parent_key=None):
    """
    Converts a nested hierarchy of key/value object (e.g. a dict of dicts) into a flat (i.e. non-nested) dict.

    :param d: the dict (or any other instance of collections.MutableMapping) to be flattened.
    :param separator: the separator to use when concatenating nested key names into flattened key names.
    :param parent_key: used internally for recursion.
    :return: a flattened dict (i.e. containing no nested dicts as values).
    """
    if separator is None:
        separator = '_'
    if parent_key is None:
        parent_key = ''

    dict_type = dict if d is None else type(d)

    items = []
    for k, v in d.items():
        new_key = parent_key + separator + k if parent_key else k
        if isinstance(v, MutableMapping):
            items.extend(flatten(v, separator=separator, parent_key=new_key).items())
        else:
            items.append((new_key, v))
    return dict_type(items)