class_docstr: Associative operations, can separate noncommutative and
  commutative parts.
  
  (a op b) op c == a op (b op c) == a op b op c.
  
  Base class for Add and Mul.
  
  This is an abstract base class, concrete derived classes must define
  the attribute `identity`.
  
  .. deprecated:: 1.7
  
     Using arguments that aren't subclasses of :class:`~.Expr` in core
     operators (:class:`~.Mul`, :class:`~.Add`, and :class:`~.Pow`) is
     deprecated. See :ref:`non-expr-args-deprecated` for details.
  
  Parameters
  ==========
  
  *args :
      Arguments which are operated
  
  evaluate : bool, optional
      Evaluate the operation. If not passed, refer to ``global_parameters.evaluate``.
docstr: Helper for .has() that checks for containment of
  subexpressions within an expr by using sets of args
  of similar nodes, e.g. x + 1 in x + y + 1 checks
  to see that {x, 1} & {x, y, 1} == {x, 1}
docstr_tok: ["Helper","for",".has","(",")","that","checks","for","containment","of","subexpressions","within","an","expr","by","using","sets","of","args","of","similar","nodes",",","e.g",".","x","+","1","in","x","+","y","+","1","checks","to","see","that","{","x",",","1","}","&","{","x",",","y",",","1","}","==","{","x",",","1","}"]
code: def _has_matcher(self):
      """Helper for .has() that checks for containment of
      subexpressions within an expr by using sets of args
      of similar nodes, e.g. x + 1 in x + y + 1 checks
      to see that {x, 1} & {x, y, 1} == {x, 1}
      """
  
      def _ncsplit(expr):
          # this is not the same as args_cnc because here
          # we don't assume expr is a Mul -- hence deal with args --
          # and always return a set.
          cpart, ncpart = sift(
              expr.args,
              lambda arg: arg.is_commutative is True,
              binary=True,
          )
          return set(cpart), ncpart
  
      c, nc = _ncsplit(self)
      cls = self.__class__
  
      def is_in(expr):
          if isinstance(expr, cls):
              if expr == self:
                  return True
              _c, _nc = _ncsplit(expr)
              if (c & _c) == c:
                  if not nc:
                      return True
                  elif len(nc) <= len(_nc):
                      for i in range(len(_nc) - len(nc) + 1):
                          if _nc[i : i + len(nc)] == nc:
                              return True
          return False
  
      return is_in
  
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 AssocOp obj's underlying member method code with example usage: obj._has_matcher() and returns: is_in, set,  ncpart, False, True, True, True