docs: def _make_constants(func, builtin_only=False, stoplist=None, verbose=None):
      """Generate new function where code is an input function code with all
      LOAD_GLOBAL statements changed to LOAD_CONST statements.
  
      :param function func: code function to transform.
      :param bool builtin_only: only transform builtin objects.
      :param list stoplist: attribute names to not transform.
      :param function verbose: logger function which takes in parameter a message
  
      .. warning::
          Be sure global attributes to transform are not resolved dynamically."""
  
      result = func
  
      if stoplist is None:
          stoplist = []
  
      try:
          fcode = func.__code__
      except AttributeError:
          return func        # Jython doesn't have a __code__ attribute.
      newcode = list(fcode.co_code) if PY3 else [ord(co) for co in fcode.co_code]
      newconsts = list(fcode.co_consts)
      names = fcode.co_names
      codelen = len(newcode)
  
      env = vars(builtins).copy()
      if builtin_only:
          stoplist = dict.fromkeys(stoplist)
          stoplist.update(func.__globals__)
      else:
          env.update(func.__globals__)
  
      # First pass converts global lookups into constants
      changed = False
      i = 0
      while i < codelen:
          opcode = newcode[i]
          if opcode in (EXTENDED_ARG, STORE_GLOBAL):
              return func    # for simplicity, only optimize common cases
          if opcode == LOAD_GLOBAL:
              oparg = newcode[i + 1] + (newcode[i + 2] << 8)
              name = fcode.co_names[oparg]
              if name in env and name not in stoplist:
                  value = env[name]
                  for pos, val in enumerate(newconsts):
                      if val is value:
                          break
                  else:
                      pos = len(newconsts)
                      newconsts.append(value)
                  newcode[i] = LOAD_CONST
                  newcode[i + 1] = pos & 0xFF
                  newcode[i + 2] = pos >> 8
                  changed = True
                  if verbose is not None:
                      verbose("{0} --> {1}".format(name, value))
          i += 1
          if opcode >= HAVE_ARGUMENT:
              i += 2
  
      # Second pass folds tuples of constants and constant attribute lookups
      i = 0
      while i < codelen:
  
          newtuple = []
          while newcode[i] == LOAD_CONST:
              oparg = newcode[i + 1] + (newcode[i + 2] << 8)
              newtuple.append(newconsts[oparg])
              i += 3
  
          opcode = newcode[i]
          if not newtuple:
              i += 1
              if opcode >= HAVE_ARGUMENT:
                  i += 2
              continue
  
          if opcode == LOAD_ATTR:
              obj = newtuple[-1]
              oparg = newcode[i + 1] + (newcode[i + 2] << 8)
              name = names[oparg]
              try:
                  value = getattr(obj, name)
              except AttributeError:
                  continue
              deletions = 1
  
          elif opcode == BUILD_TUPLE:
              oparg = newcode[i + 1] + (newcode[i + 2] << 8)
              if oparg != len(newtuple):
                  continue
              deletions = len(newtuple)
              value = tuple(newtuple)
  
          else:
              continue
  
          reljump = deletions * 3
          newcode[i - reljump] = JUMP_FORWARD
          newcode[i - reljump + 1] = (reljump - 3) & 0xFF
          newcode[i - reljump + 2] = (reljump - 3) >> 8
  
          nclen = len(newconsts)
          newconsts.append(value)
          newcode[i] = LOAD_CONST
          newcode[i + 1] = nclen & 0xFF
          newcode[i + 2] = nclen >> 8
          i += 3
          changed = True
          if verbose is not None:
              verbose("new folded constant:{0}".format(value))
  
      if changed:
  
          codeobj = getcodeobj(newconsts, newcode, fcode, fcode)
  
          result = type(func)(
              codeobj,
              func.__globals__, func.__name__, func.__defaults__, func.__closure__
          )
  
          # set func attributes to result
          for prop in WRAPPER_ASSIGNMENTS:
              try:
                  attr = getattr(func, prop)
              except AttributeError:
                  pass
              else:
                  setattr(result, prop, attr)
  
      return result