code: def replace(expression: Expression, position: Sequence[int], replacement: Replacement) -> Replacement:
      r
      if len(position) == 0:
          return replacement
      if not isinstance(expression, Operation):
          raise IndexError("Invalid position {!r} for expression {!s}".format(position, expression))
      if position[0] >= op_len(expression):
          raise IndexError("Position {!r} out of range for expression {!s}".format(position, expression))
      pos = position[0]
      operands = list(op_iter(expression))
      subexpr = replace(operands[pos], position[1:], replacement)
      if isinstance(subexpr, Sequence):
          new_operands = tuple(operands[:pos]) + tuple(subexpr) + tuple(operands[pos + 1:])
          return create_operation_expression(expression, new_operands)
      operands[pos] = subexpr
      return create_operation_expression(expression, operands)
docs: r"""Replaces the subexpression of `expression` at the given `position` with the given `replacement`.
  
      The original `expression` itself is not modified, but a modified copy is returned. If the replacement
      is a list of expressions, it will be expanded into the list of operands of the respective operation:
  
      >>> print(replace(f(a), (0, ), [b, c]))
      f(b, c)
  
      Parameters:
          expression:
              An :class:`Expression` where a (sub)expression is to be replaced.
          position:
              A tuple of indices, e.g. the empty tuple refers to the `expression` itself,
              `(0, )` refers to the first child (operand) of the `expression`, `(0, 0)` to the first
              child of the first child etc.
          replacement:
              Either an :class:`Expression` or a list of :class:`Expression`\s to be
              inserted into the `expression` instead of the original expression at that `position`.
  
      Returns:
          The resulting expression from the replacement.
  
      Raises:
          IndexError: If the position is invalid or out of range.