Repository: sympy/sympy
File: sympy/core/expr.py (Python)

Code before:
        for d in deps:
            if isinstance(d, Symbol):  # Symbol.is_Symbol is True
                sym.add(d)
            else:
                other.append(d)

        def has(e):
            """return the standard has() if there are no literal symbols, else
            check to see that symbol-deps are in the free symbols."""
            has_other = e.has(*other)
            if not sym:
                return has_other
            return has_other or e.has(*(e.free_symbols & sym))

        if want is Add and not self.is_Add:
            if has(self):
                return (S.Zero, self)
            else:
                return (self, S.Zero)
        elif want is Mul and not self.is_Mul:
            if has(self):
                return (S.One, self)
            else:
                return (self, S.One)
        else:
            if issubclass(func, Add):
                args = list(self.args)
            else:
                args, nc = self.args_cnc()

        d = sift(args, has)
        depend = d[True]
        indep = d[False]
        if issubclass(func, Add):  # all terms were treated as commutative
            return (func(*indep), _unevaluated_Add(*depend))
        else:  # handle noncommutative by stopping at first dependent term
            for i, n in enumerate(nc):
                if has(n):
                    depend.extend(nc[i:])
                    break
                indep.append(n)
            return func(*indep), _unevaluated_Mul(*depend)

    def as_real_imag(self, deep=True, **hints) -> tuple[Expr, Expr]:
        """Performs complex expansion on 'self' and returns a tuple
           containing collected both real and imaginary parts. This
           method cannot be confused with re() and im() functions,
           which does not perform complex expansion at evaluation.

           However it is possible to expand both re() and im()
           functions and get exactly the same results as with

Review comment (refactor):
It is generally better not to use `issubclass`. In principle it should be possible for there to be something that is not a subclass but that behaves like an Add and has properties like `is_Add`. The preceding lines have already ruled out the case where `want` and `self` are not the same type so this can either check `want is Add` or `self.is_Add`. Even if it wants to check for a subclass it would be better to write `isinstance(self, Add)` but I would use `self.is_Add` which is mostly equivalent but allows for the possibility of a non-subclass.

The code as it is has been written by someone who values DRY above readability. It is better just to repeat a few lines of simple readable code than to try to abstract everything. It would be cleaner just to have two separate branches starting above for the whole rest of the function:
```python
if want is Add:
    if not self.is_Add: 
        ...
    ...
    return Add(...) ...
elif want is Mul:
    ...
```
(Of course this shows again that it should really be two separate functions/methods rather than a single method with two different behaviours.)

Code after:
            as_Add = self.is_Add

        syms, other = _sift_true_false(deps, lambda d: isinstance(d, Symbol))
        syms_set = set(syms)

        if other:
            def has(e):
                return e.has_xfree(syms_set) or e.has(*other)
        else:
            def has(e):
                return e.has_xfree(syms_set)

        if as_Add:
            if not self.is_Add:
                if has(self):
                    return (S.Zero, self)
                else:
                    return (self, S.Zero)

            depend, indep = _sift_true_false(self.args, has)
            return (self.func(*indep), _unevaluated_Add(*depend))

        else:
            if not self.is_Mul:
                if has(self):
                    return (S.One, self)
                else:
                    return (self, S.One)

            args, nc = self.args_cnc()
            depend, indep = _sift_true_false(args, has)

            # handle noncommutative by stopping at first dependent term
            for i, n in enumerate(nc):
                if has(n):
                    depend.extend(nc[i:])
                    break
                indep.append(n)

            return self.func(*indep), _unevaluated_Mul(*depend)

    def as_real_imag(self, deep=True, **hints) -> tuple[Expr, Expr]:
        """Performs complex expansion on 'self' and returns a tuple
           containing collected both real and imaginary parts. This
           method cannot be confused with re() and im() functions,
           which does not perform complex expansion at evaluation.

           However it is possible to expand both re() and im()
           functions and get exactly the same results as with
           a single call to this function.