class_docstr: Generic printer
  
  Its job is to provide infrastructure for implementing new printers easily.
  
  If you want to define your custom Printer or your custom printing method
  for your custom class then see the example above: printer_example_ .
docstr: Internal dispatcher
  
  Tries the following concepts to print an expression:
      1. Let the object print itself if it knows how.
      2. Take the best fitting method defined in the printer.
      3. As fall-back use the emptyPrinter method for the printer.
docstr_tok: ["Internal","dispatcher","Tries","the","following","concepts","to","print","an","expression",":","1",".","Let","the","object","print","itself","if","it","knows","how",".","2",".","Take","the","best","fitting","method","defined","in","the","printer",".","3",".","As","fall-back","use","the","emptyPrinter","method","for","the","printer","."]
code: def _print(self, expr, **kwargs) -> str:
      """Internal dispatcher
  
      Tries the following concepts to print an expression:
          1. Let the object print itself if it knows how.
          2. Take the best fitting method defined in the printer.
          3. As fall-back use the emptyPrinter method for the printer.
      """
      self._print_level += 1
      try:
          # If the printer defines a name for a printing method
          # (Printer.printmethod) and the object knows for itself how it
          # should be printed, use that method.
          if self.printmethod and hasattr(expr, self.printmethod):
              if not (
                  isinstance(expr, type) and issubclass(expr, Basic)
              ):
                  return getattr(expr, self.printmethod)(self, **kwargs)
  
          # See if the class of expr is known, or if one of its super
          # classes is known, and use that print function
          # Exception: ignore the subclasses of Undefined, so that, e.g.,
          # Function('gamma') does not get dispatched to _print_gamma
          classes = type(expr).__mro__
          if AppliedUndef in classes:
              classes = classes[classes.index(AppliedUndef) :]
          if UndefinedFunction in classes:
              classes = classes[classes.index(UndefinedFunction) :]
          # Another exception: if someone subclasses a known function, e.g.,
          # gamma, and changes the name, then ignore _print_gamma
          if Function in classes:
              i = classes.index(Function)
              classes = (
                  tuple(
                      c
                      for c in classes[:i]
                      if c.__name__ == classes[0].__name__
                      or c.__name__.endswith("Base")
                  )
                  + classes[i:]
              )
          for cls in classes:
              printmethodname = "_print_" + cls.__name__
              printmethod = getattr(self, printmethodname, None)
              if printmethod is not None:
                  return printmethod(expr, **kwargs)
          # Unknown object, fall back to the emptyPrinter.
          return self.emptyPrinter(expr)
      finally:
          self._print_level -= 1
  
imports: from __future__ import annotations
  import sys
  from typing import Any, Type
  import inspect
  from contextlib import contextmanager
  from functools import cmp_to_key, update_wrapper
  from sympy.core.add import Add
  from sympy.core.basic import Basic
  from sympy.core.function import AppliedUndef, UndefinedFunction, Function
label_desc: Use image node_id 6 for calling the Printer obj's underlying member method code with example usage: obj._print(expr) and returns: self, getattr, printmethod