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
docstr: Select the handler class, and return its handler method.
docstr_tok: ["Select","the","handler","class",",","and","return","its","handler","method","."]
code: def dispatch(self, handlers):
      """
      Select the handler class, and return its handler method.
      """
  
      # Quick exit for the case where all handlers are same
      if len(handlers) == 1:
          (h,) = handlers
          if not isinstance(h, type):
              raise RuntimeError(
                  "Handler {!r} is not a type.".format(h)
              )
          return h
  
      # Recursively select with registered binary priority
      for i, typ in enumerate(handlers):
          if not isinstance(typ, type):
              raise RuntimeError(
                  "Handler {!r} is not a type.".format(typ)
              )
  
          if i == 0:
              handler = typ
          else:
              prev_handler = handler
              handler = self._dispatcher.dispatch(prev_handler, typ)
  
              if not isinstance(handler, type):
                  raise RuntimeError(
                      "Dispatcher for {!r} and {!r} must return a type, but got {!r}".format(
                          prev_handler, typ, handler
                      )
                  )
  
      # return handler class
      return handler
  
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 5 for calling the AssocOpDispatcher obj's underlying member method code with example usage: obj.dispatch(handlers) and returns: handler, h