def cleanup(data, clean='layers', keep=None, copy=False):
    """Deletes attributes not needed.

    Arguments
    ---------
    data: :class:`~anndata.AnnData`
        Annotated data matrix.
    clean: `str` or list of `str` (default: `layers`)
        Which attributes to consider for freeing memory.
    keep: `str` or list of `str` (default: None)
        Which attributes to keep.
    copy: `bool` (default: `False`)
        Return a copy instead of writing to adata.

    Returns
    -------
    Returns or updates `adata` with selection of attributes kept.
    """
    adata = data.copy() if copy else data

    keep = list([keep]) if isinstance(keep, str) else list() if keep is None else list(keep)
    keep.extend(['spliced', 'unspliced', 'Ms', 'Mu', 'clusters', 'neighbors'])

    ann_dict = {'obs': adata.obs_keys(), 'var': adata.var_keys(),
                'uns': adata.uns_keys(), 'layers': list(adata.layers.keys())}

    if 'all' not in clean:
        ann_dict = {ann: values for (ann, values) in ann_dict.items() if ann in clean}

    for (ann, values) in ann_dict.items():
        for value in values:
            if value not in keep: del(getattr(adata, ann)[value])

    return adata if copy else None