def getter(x, k: str, *args):
    """
    get an attribute (from an object) or key (from a dict-like object)

    `getter(x, k)` raise KeyError if `k` not present

    `getter(x, k, default)` return default if `k` not present

    This is a convenience function that allows you to interact the same with
    an object or a dictionary

    Parameters
    ----------
    x : object, dict
        Item to get attribute from
    k : str
        Key or attribute name
    default : optional
        Default value if `k` not present

    Returns
    -------
    val : object
        Associated value
    """
    try:
        try:
            # assume x is dict-like
            val = x[k]
        except TypeError:
            # x is not dict-like, try to get an attribute
            try:
                val = getattr(x, k)
            except AttributeError:
                # Attribute not present
                raise KeyError
    except KeyError as e:
        if len(args) > 0:
            return args[0]
        else:
            raise (e)
    return val