class_docstr: Handler dispatcher for associative operators
  
  .. notes::
     This approach is experimental, and can be replaced or deleted in the future.
     See https://github.com/sympy/sympy/pull/19463.
  
  Explanation
  ===========
  
  If arguments of different types are passed, the classes which handle the operation for each type
  are collected. Then, a class which performs the operation is selected by recursive binary dispatching.
  Dispatching relation can be registered by ``register_handlerclass`` method.
  
  Priority registration is unordered. You cannot make ``A*B`` and ``B*A`` refer to
  different handler classes. All logic dealing with the order of arguments must be implemented
  in the handler class.
  
  Examples
  ========
  
  >>> from sympy import Add, Expr, Symbol
  >>> from sympy.core.add import add
  
  >>> class NewExpr(Expr):
  ...     @property
  ...     def _add_handler(self):
  ...         return NewAdd
  >>> class NewAdd(NewExpr, Add):
  ...     pass
  >>> add.register_handlerclass((Add, NewAdd), NewAdd)
  
  >>> a, b = Symbol('a'), NewExpr()
  >>> add(a, b) == NewAdd(a, b)
  True
code: def __doc__(self):
      docs = [
          "Multiply dispatched associative operator: %s" % self.name,
          "Note that support for this is experimental, see the docs for :class:`AssocOpDispatcher` for details",
      ]
  
      if self.doc:
          docs.append(self.doc)
  
      s = "Registered handler classes\n"
      s += "=" * len(s)
      docs.append(s)
  
      amb_sigs = []
  
      typ_sigs = defaultdict(list)
      for sigs in self._dispatcher.ordering[::-1]:
          key = self._dispatcher.funcs[sigs]
          typ_sigs[key].append(sigs)
  
      for typ, sigs in typ_sigs.items():
          sigs_str = ", ".join(
              "<%s>" % str_signature(sig) for sig in sigs
          )
  
          if isinstance(typ, RaiseNotImplementedError):
              amb_sigs.append(sigs_str)
              continue
  
          s = "Inputs: %s\n" % sigs_str
          s += "-" * len(s) + "\n"
          s += typ.__name__
          docs.append(s)
  
      if amb_sigs:
          s = "Ambiguous handler classes\n"
          s += "=" * len(s)
          docs.append(s)
  
          s = "\n".join(amb_sigs)
          docs.append(s)
  
      return "\n\n".join(docs)
  
imports: from __future__ import annotations
  from operator import attrgetter
  from collections import defaultdict
  from sympy.utilities.exceptions import sympy_deprecation_warning
  from .sympify import _sympify, sympify
  from .basic import Basic
  from .cache import cacheit
  from .sorting import ordered
  from .logic import fuzzy_and
  from .parameters import global_parameters
  from sympy.utilities.iterables import sift
  from sympy.multipledispatch.dispatcher import Dispatcher, ambiguity_register_error_ignore_dup, str_signature, RaiseNotImplementedError
label_desc: Use image node_id 6 for calling the AssocOpDispatcher obj's underlying member method code with example usage: obj.__doc__() and returns: str