def get_params(parameters, deep=True, keepcontainers=True):
    """Depth first redundantly flatten a nested dictionary.

    Arguments
    ---------
    parameters : dict
        The dictionary to traverse and linearize.

    deep : bool, default=True
        Whether to perform depth first traversal of nested dictionaries
        or not.

    keepcontainers : bool, default=True
        Whether to keep return the nested containers (dicts) or not.
        Effective only if `deep` is `True`.

    Details
    -------
    Adapted from scikit's BaseEstimator. Does not handle recursive
    dictionaries.
    """
    out = {}
    for key in parameters:
        value = parameters[key]
        if deep and isinstance(value, dict):
            nested = get_params(value, deep=True, keepcontainers=keepcontainers)
            out.update((key + '__' + k, val) for k, val in nested.items())
            if not keepcontainers:
                continue

        out[key] = value

    return out