class_docstr: A printer to convert expressions to strings of Julia code.
class_docstr_tok: ["A","printer","to","convert","expressions","to","strings","of","Julia","code","."]
code: def _print_Mul(self, expr):
      # print complex numbers nicely in Julia
      if (
          expr.is_number
          and expr.is_imaginary
          and expr.as_coeff_Mul()[0].is_integer
      ):
          return "%sim" % self._print(-S.ImaginaryUnit * expr)
  
      # cribbed from str.py
      prec = precedence(expr)
  
      c, e = expr.as_coeff_Mul()
      if c < 0:
          expr = _keep_coeff(-c, e)
          sign = "-"
      else:
          sign = ""
  
      a = []  # items in the numerator
      b = []  # items that are in the denominator (if any)
  
      pow_paren = (
          []
      )  # Will collect all pow with more than one base element and exp = -1
  
      if self.order not in ("old", "none"):
          args = expr.as_ordered_factors()
      else:
          # use make_args in case expr was something like -x -> x
          args = Mul.make_args(expr)
  
      # Gather args for numerator/denominator
      for item in args:
          if (
              item.is_commutative
              and item.is_Pow
              and item.exp.is_Rational
              and item.exp.is_negative
          ):
              if item.exp != -1:
                  b.append(Pow(item.base, -item.exp, evaluate=False))
              else:
                  if len(item.args[0].args) != 1 and isinstance(
                      item.base, Mul
                  ):  # To avoid situations like #14160
                      pow_paren.append(item)
                  b.append(Pow(item.base, -item.exp))
          elif (
              item.is_Rational
              and item is not S.Infinity
              and item.p == 1
          ):
              # Save the Rational type in julia Unless the numerator is 1.
              # For example:
              # julia_code(Rational(3, 7)*x) --> (3 // 7) * x
              # julia_code(x/3) --> x / 3 but not x * (1 // 3)
              b.append(Rational(item.q))
          else:
              a.append(item)
  
      a = a or [S.One]
  
      a_str = [self.parenthesize(x, prec) for x in a]
      b_str = [self.parenthesize(x, prec) for x in b]
  
      # To parenthesize Pow with exp = -1 and having more than one Symbol
      for item in pow_paren:
          if item.base in b:
              b_str[b.index(item.base)] = (
                  "(%s)" % b_str[b.index(item.base)]
              )
  
      # from here it differs from str.py to deal with "*" and ".*"
      def multjoin(a, a_str):
          # here we probably are assuming the constants will come first
          r = a_str[0]
          for i in range(1, len(a)):
              mulsym = "*" if a[i - 1].is_number else ".*"
              r = "%s %s %s" % (r, mulsym, a_str[i])
          return r
  
      if not b:
          return sign + multjoin(a, a_str)
      elif len(b) == 1:
          divsym = "/" if b[0].is_number else "./"
          return "%s %s %s" % (
              sign + multjoin(a, a_str),
              divsym,
              b_str[0],
          )
      else:
          divsym = "/" if all(bi.is_number for bi in b) else "./"
          return "%s %s (%s)" % (
              sign + multjoin(a, a_str),
              divsym,
              multjoin(b, b_str),
          )
  
imports: from __future__ import annotations
  from typing import Any
  from sympy.core import Mul, Pow, S, Rational
  from sympy.core.mul import _keep_coeff
  from sympy.core.numbers import equal_valued
  from sympy.printing.codeprinter import CodePrinter
  from sympy.printing.precedence import precedence, PRECEDENCE
  from re import search
label_desc: Use image node_id 9 for calling the JuliaCodePrinter obj's underlying member method code with example usage: obj._print_Mul(expr) and returns: unknown, r, unknown, unknown, unknown