Return a unicode 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
        unicode_sub_super (bool): Whether to try to use unicode symbols for
            sub- or superscripts if possible
        unicode_op_hats (bool): Whether to draw unicode hats on single-letter
            operator symbols

    Examples:

        >>> A = OperatorSymbol('A', hs=1); B = OperatorSymbol('B', hs=1)
        >>> unicode(A + B)
        'Â⁽¹⁾ + B̂⁽¹⁾'
        >>> unicode(A + B, cache={A: 'A', B: 'B'})
        'A + B'
        >>> unicode(A + B, show_hs_label='subscript')
        'Â₍₁₎ + B̂₍₁₎'
        >>> unicode(A + B, show_hs_label=False)
        'Â + B̂'
        >>> unicode(LocalSigma(0, 1, hs=1))
        '|0⟩⟨1|⁽¹⁾'
        >>> unicode(LocalSigma(0, 1, hs=1), sig_as_ketbra=False)
        'σ̂_0,1^(1)'
        >>> unicode(A + B, unicode_sub_super=False)
        'Â^(1) + B̂^(1)'
        >>> unicode(A + B, unicode_op_hats=False)
        'A⁽¹⁾ + B⁽¹⁾'

    Note that the accepted parameters and their default values may be changed
    through :func:`init_printing` or :func:`configure_printing`

def unicode(expr, cache=None, **settings):
    """Return a unicode 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
        unicode_sub_super (bool): Whether to try to use unicode symbols for
            sub- or superscripts if possible
        unicode_op_hats (bool): Whether to draw unicode hats on single-letter
            operator symbols

    Examples:

        >>> A = OperatorSymbol('A', hs=1); B = OperatorSymbol('B', hs=1)
        >>> unicode(A + B)
        'Â⁽¹⁾ + B̂⁽¹⁾'
        >>> unicode(A + B, cache={A: 'A', B: 'B'})
        'A + B'
        >>> unicode(A + B, show_hs_label='subscript')
        'Â₍₁₎ + B̂₍₁₎'
        >>> unicode(A + B, show_hs_label=False)
        'Â + B̂'
        >>> unicode(LocalSigma(0, 1, hs=1))
        '|0⟩⟨1|⁽¹⁾'
        >>> unicode(LocalSigma(0, 1, hs=1), sig_as_ketbra=False)
        'σ̂_0,1^(1)'
        >>> unicode(A + B, unicode_sub_super=False)
        'Â^(1) + B̂^(1)'
        >>> unicode(A + B, unicode_op_hats=False)
        'A⁽¹⁾ + B⁽¹⁾'

    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 unicode.printer.doprint(expr)
        else:
            printer = unicode._printer_cls(cache, settings)
            return printer.doprint(expr)
    except AttributeError:
        # init_printing was not called. Setting up defaults
        unicode._printer_cls = QnetUnicodePrinter
        unicode.printer = unicode._printer_cls()
        return unicode(expr, cache, **settings)