class_docstr: Represents an unevaluated limit.
  
  Examples
  ========
  
  >>> from sympy import Limit, sin
  >>> from sympy.abc import x
  >>> Limit(sin(x)/x, x, 0)
  Limit(sin(x)/x, x, 0, dir='+')
  >>> Limit(1/x, x, 0, dir="-")
  Limit(1/x, x, 0, dir='-')
class_docstr_tok: ["Represents","an","unevaluated","limit",".","Examples","========",">",">",">","from","sympy","import","Limit",",","sin",">",">",">","from","sympy.abc","import","x",">",">",">","Limit","(","sin","(","x",")","\/x",",","x",",","0",")","Limit","(","sin","(","x",")","\/x",",","x",",","0",",","dir='+","'",")",">",">",">","Limit","(","1\/x",",","x",",","0",",","dir=","''","-","''",")","Limit","(","1\/x",",","x",",","0",",","dir='-","'",")"]
docstr: Evaluates the limit.
  
  Parameters
  ==========
  
  deep : bool, optional (default: True)
      Invoke the ``doit`` method of the expressions involved before
      taking the limit.
  
  hints : optional keyword arguments
      To be passed to ``doit`` methods; only used if deep is True.
docstr_tok: ["Evaluates","the","limit",".","Parameters","==========","deep",":","bool",",","optional","(","default",":","True",")","Invoke","the","``","doit","``","method","of","the","expressions","involved","before","taking","the","limit",".","hints",":","optional","keyword","arguments","To","be","passed","to","``","doit","``","methods",";","only","used","if","deep","is","True","."]
code: def doit(self, **hints):
      """Evaluates the limit.
  
      Parameters
      ==========
  
      deep : bool, optional (default: True)
          Invoke the ``doit`` method of the expressions involved before
          taking the limit.
  
      hints : optional keyword arguments
          To be passed to ``doit`` methods; only used if deep is True.
      """
  
      e, z, z0, dir = self.args
  
      if str(dir) == "+-":
          r = limit(e, z, z0, dir="+")
          l = limit(e, z, z0, dir="-")
          if isinstance(r, Limit) and isinstance(l, Limit):
              if r.args[0] == l.args[0]:
                  return self
          if r == l:
              return l
          if r.is_infinite and l.is_infinite:
              return S.ComplexInfinity
          raise ValueError(
              "The limit does not exist since "
              "left hand limit = %s and right hand limit = %s" % (l, r)
          )
  
      if z0 is S.ComplexInfinity:
          raise NotImplementedError(
              "Limits at complex " "infinity are not implemented"
          )
  
      if z0.is_infinite:
          cdir = sign(z0)
          cdir = cdir / abs(cdir)
          e = e.subs(z, cdir * z)
          dir = "-"
          z0 = S.Infinity
  
      if hints.get("deep", True):
          e = e.doit(**hints)
          z = z.doit(**hints)
          z0 = z0.doit(**hints)
  
      if e == z:
          return z0
  
      if not e.has(z):
          return e
  
      if z0 is S.NaN:
          return S.NaN
  
      if e.has(*_illegal):
          return self
  
      if e.is_Order:
          return Order(limit(e.expr, z, z0), *e.args[1:])
  
      cdir = 0
      if str(dir) == "+":
          cdir = 1
      elif str(dir) == "-":
          cdir = -1
  
      def set_signs(expr):
          if not expr.args:
              return expr
          newargs = tuple(set_signs(arg) for arg in expr.args)
          if newargs != expr.args:
              expr = expr.func(*newargs)
          abs_flag = isinstance(expr, Abs)
          arg_flag = isinstance(expr, arg)
          sign_flag = isinstance(expr, sign)
          if abs_flag or sign_flag or arg_flag:
              sig = limit(expr.args[0], z, z0, dir)
              if sig.is_zero:
                  sig = limit(1 / expr.args[0], z, z0, dir)
              if sig.is_extended_real:
                  if (sig < 0) == True:
                      return (
                          -expr.args[0]
                          if abs_flag
                          else S.NegativeOne
                          if sign_flag
                          else S.Pi
                      )
                  elif (sig > 0) == True:
                      return (
                          expr.args[0]
                          if abs_flag
                          else S.One
                          if sign_flag
                          else S.Zero
                      )
          return expr
  
      if e.has(Float):
          # Convert floats like 0.5 to exact SymPy numbers like S.Half, to
          # prevent rounding errors which can lead to unexpected execution
          # of conditional blocks that work on comparisons
          # Also see comments in https://github.com/sympy/sympy/issues/19453
          from sympy.simplify.simplify import nsimplify
  
          e = nsimplify(e)
      e = set_signs(e)
  
      if e.is_meromorphic(z, z0):
          if z0 is S.Infinity:
              newe = e.subs(z, 1 / z)
              # cdir changes sign as oo- should become 0+
              cdir = -cdir
          else:
              newe = e.subs(z, z + z0)
          try:
              coeff, ex = newe.leadterm(z, cdir=cdir)
          except ValueError:
              pass
          else:
              if ex > 0:
                  return S.Zero
              elif ex == 0:
                  return coeff
              if cdir == 1 or not (int(ex) & 1):
                  return S.Infinity * sign(coeff)
              elif cdir == -1:
                  return S.NegativeInfinity * sign(coeff)
              else:
                  return S.ComplexInfinity
  
      if z0 is S.Infinity:
          if e.is_Mul:
              e = factor_terms(e)
          newe = e.subs(z, 1 / z)
          # cdir changes sign as oo- should become 0+
          cdir = -cdir
      else:
          newe = e.subs(z, z + z0)
      try:
          coeff, ex = newe.leadterm(z, cdir=cdir)
      except (ValueError, NotImplementedError, PoleError):
          # The NotImplementedError catching is for custom functions
          from sympy.simplify.powsimp import powsimp
  
          e = powsimp(e)
          if e.is_Pow:
              r = self.pow_heuristics(e)
              if r is not None:
                  return r
          try:
              coeff = newe.as_leading_term(z, cdir=cdir)
              if coeff != newe and (
                  coeff.has(exp) or coeff.has(S.Exp1)
              ):
                  return gruntz(
                      coeff, z, 0, "-" if re(cdir).is_negative else "+"
                  )
          except (ValueError, NotImplementedError, PoleError):
              pass
      else:
          if isinstance(coeff, AccumBounds) and ex == S.Zero:
              return coeff
          if coeff.has(
              S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.NaN
          ):
              return self
          if not coeff.has(z):
              if ex.is_positive:
                  return S.Zero
              elif ex == 0:
                  return coeff
              elif ex.is_negative:
                  if cdir == 1:
                      return S.Infinity * sign(coeff)
                  elif cdir == -1:
                      return (
                          S.NegativeInfinity
                          * sign(coeff)
                          * S.NegativeOne ** (S.One + ex)
                      )
                  else:
                      return S.ComplexInfinity
              else:
                  raise NotImplementedError(
                      "Not sure of sign of %s" % ex
                  )
  
      # gruntz fails on factorials but works with the gamma function
      # If no factorial term is present, e should remain unchanged.
      # factorial is defined to be zero for negative inputs (which
      # differs from gamma) so only rewrite for positive z0.
      if z0.is_extended_positive:
          e = e.rewrite(factorial, gamma)
  
      l = None
  
      try:
          r = gruntz(e, z, z0, dir)
          if r is S.NaN or l is S.NaN:
              raise PoleError()
      except (PoleError, ValueError):
          if l is not None:
              raise
          r = heuristics(e, z, z0, dir)
          if r is None:
              return self
  
      return r
  
file_path: sympy/sympy/series/limits.py
imports: from sympy.calculus.accumulationbounds import AccumBounds
  from sympy.core import S, Symbol, Add, sympify, Expr, PoleError, Mul
  from sympy.core.exprtools import factor_terms
  from sympy.core.numbers import Float, _illegal
  from sympy.functions.combinatorial.factorials import factorial
  from sympy.functions.elementary.complexes import Abs, sign, arg, re
  from sympy.functions.elementary.exponential import exp, log
  from sympy.functions.special.gamma_functions import gamma
  from sympy.polys import PolynomialError, factor
  from sympy.series.order import Order
  from .gruntz import gruntz
label_desc: Use image node_id 4 for calling the Limit obj's underlying member method code with example usage: obj.doit() and returns: r, z0, e, S, self, Order, expr, l, S, expr, coeff, self, self, S, unknown, S, self, unknown, coeff, unknown, S, r, gruntz, coeff, unknown, unknown, unknown, S