What goes into the script
A .ipynb file is JSON: a list of cells plus their saved outputs. Code cells are copied as they are, separated by two blank lines. Markdown cells become comment lines starting with #, or are dropped if you only want the code. Raw cells are treated the same way as markdown. Outputs — printed results, tables, charts — and execution counts are not included, because a script recreates them by running.
With “Mark cells with # %%” on, every cell starts with # %% (and markdown cells with # %% [markdown]). VS Code, Spyder and PyCharm show each marked block as a cell you can run on its own, and Jupytext can turn the file back into a notebook.
Magics and shell commands
Notebooks run on IPython, which accepts syntax Python does not: line magics such as %matplotlib inline, shell commands such as !pip install pandas, captures such as files = !ls, and help lookups such as len?. Left in, any of these is a syntax error in a .py file, so they are commented out and counted.
Cell magics are handled by what the cell contains. In %%time, %%timeit, %%capture, %%prun, %%debug, %%memit and %%skip cells the body is Python, so only the %% line is commented. Cells such as %%bash, %%html, %%sql or %%writefile hold another language or file content, so the whole cell is commented.
Compared with nbconvert
Running jupyter nbconvert --to script notebook.ipynb does a similar job on your own computer, but it rewrites magics as get_ipython() calls, so the result only runs under IPython. This tool comments them out instead, so the script runs with plain python — and you can see at a glance what used to be a magic.