def ascii(expr, cache=None, **settings):
    """Return an ASCII representation of the given object / expression

    Args:
        expr: Expression to print
        cache (dict or None): dictionary to use for caching
        show_hs_label (bool or str): Whether to a label for the Hilbert space
            of `expr`. By default (``show_hs_label=True``), the label is shown
            as a superscript. It can be shown as a subscript with
            ``show_hs_label='subscript'`` or suppressed entirely
            (``show_hs_label=False``)
        sig_as_ketbra (bool): Whether to render instances of
            :class:`.LocalSigma` as a ket-bra (default), or as an operator
            symbol

    Examples:

        >>> A = OperatorSymbol('A', hs=1); B = OperatorSymbol('B', hs=1)
        >>> ascii(A + B)
        'A^(1) + B^(1)'
        >>> ascii(A + B, cache={A: 'A', B: 'B'})
        'A + B'
        >>> ascii(A + B, show_hs_label='subscript')
        'A_(1) + B_(1)'
        >>> ascii(A + B, show_hs_label=False)
        'A + B'
        >>> ascii(LocalSigma(0, 1, hs=1))
        '|0><1|^(1)'
        >>> ascii(LocalSigma(0, 1, hs=1), sig_as_ketbra=False)
        'sigma_0,1^(1)'

    Note that the accepted parameters and their default values may be changed
    through :func:`init_printing` or :func:`configure_printing`
    """
    try:
        if cache is None and len(settings) == 0:
            return ascii.printer.doprint(expr)
        else:
            printer = ascii._printer_cls(cache, settings)
            return printer.doprint(expr)
    except AttributeError:
        # init_printing was not called. Setting up defaults
        ascii._printer_cls = QnetAsciiPrinter
        ascii.printer = ascii._printer_cls()
        return ascii(expr, cache, **settings)