code: def get_args(tp, evaluate=None):
      
      if NEW_TYPING:
          if evaluate is not None and not evaluate:
              raise ValueError('evaluate can only be True in Python 3.7')
          if isinstance(tp, _GenericAlias):
              res = tp.__args__
              if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis:
                  res = (list(res[:-1]), res[-1])
              return res
          return ()
      if is_classvar(tp):
          return (tp.__type__,)
      if (
          is_generic_type(tp) or is_union_type(tp) or
          is_callable_type(tp) or is_tuple_type(tp)
      ):
          tree = tp._subs_tree()
          if isinstance(tree, tuple) and len(tree) > 1:
              if not evaluate:
                  return tree[1:]
              res = _eval_args(tree[1:])
              if get_origin(tp) is Callable and res[0] is not Ellipsis:
                  res = (list(res[:-1]), res[-1])
              return res
      return ()
docs: Get type arguments with all substitutions performed. For unions,
      basic simplifications used by Union constructor are performed.
      On versions prior to 3.7 if `evaluate` is False (default),
      report result as nested tuple, this matches
      the internal representation of types. If `evaluate` is True
      (or if Python version is 3.7 or greater), then all
      type parameters are applied (this could be time and memory expensive).
      Examples::
  
          get_args(int) == ()
          get_args(Union[int, Union[T, int], str][int]) == (int, str)
          get_args(Union[int, Tuple[T, int]][str]) == (int, (Tuple, str, int))
  
          get_args(Union[int, Tuple[T, int]][str], evaluate=True) == \
                   (int, Tuple[str, int])
          get_args(Dict[int, Tuple[T, T]][Optional[int]], evaluate=True) == \
                   (int, Tuple[Optional[int], Optional[int]])
          get_args(Callable[[], T][int], evaluate=True) == ([], int,)