Addaly is in open beta. Things will change, and AI answers can be wrong — check anything that matters.

Python, From Zero, For AI

From your first line of code to your first API call.

Lesson 10 of 898 min

What happens between your file and the answer

Python is not read line by line as it runs

The common picture — Python reads line 1, does it, reads line 2 — is wrong in a way that matters later.

When you run python3 budget.py, four things happen:

  1. The whole file is read and tokenised. This is why a missing bracket on line 40 stops line 1 from running: the file never became a program.
  2. It is parsed into a tree representing the structure of the code.
  3. It is compiled to bytecode — a compact instruction set for a made-up machine.
  4. A virtual machine executes that bytecode, one instruction at a time.

The bytecode is not a secret. You can look at it:

python
import dis
dis.dis(compile("total = a + b", "<demo>", "exec"))
  LOAD_NAME                0 (a)
  LOAD_NAME                1 (b)
  BINARY_OP                0 (+)
  STORE_NAME               2 (total)

Four instructions: fetch a, fetch b, add them, store the result. This is a real skill occasionally — dis settles arguments about which of two ways of writing something does less work.

The __pycache__ folder

Import a module and Python writes the compiled bytecode into a folder called __pycache__, as a .pyc file, so the next import can skip steps 1 to 3. It checks the source file's timestamp and size and recompiles when they change.

Two practical consequences. It is always safe to delete __pycache__; the worst outcome is one slightly slower start. And it belongs in .gitignore — committing it puts machine-specific compiled files in your repository for no benefit.

The file you run directly never gets cached, only the modules it imports. That is why a large program starts faster the second time and your one-file script does not.

Why Python is slow, stated properly

"Python is slow" is repeated everywhere and almost never explained. The mechanism is this: every value is a heap-allocated object carrying its type.

When C adds two integers, the compiler already knows they are integers and emits one CPU instruction. When Python evaluates a + b, the virtual machine must: look up what a currently refers to, look up its type, find that type's addition method, do the same for b, check they are compatible, allocate a new object for the result, and update reference counts. That is dozens of machine instructions for one addition, and none of it can be skipped, because a could have been an int on the last iteration and a string on this one.

Measure it:

bash
python3 -m timeit -s "xs=range(1000000)" "sum(x*x for x in xs)"
python3 -m timeit -s "import numpy as np; xs=np.arange(1000000)" "(xs*xs).sum()"

On an ordinary laptop the first is roughly 60–90 milliseconds and the second roughly 1–2 milliseconds. That is a 50-fold difference for the same arithmetic. NumPy is not cleverer Python; the loop runs inside compiled C over a block of raw 64-bit integers with no per-value type checks and no object allocation.

Squaring ten million numbers, four waysfor loop, appending to alist900List comprehension620map() with a lambda700NumPy array, one line15milliseconds on an ordinary laptopThe first three are all Python doing the arithmetic, and they differ by less than a factor of two. Thefourth moves the loop out of Python entirely. This is why the fix for slow numeric code is almostnever a better-written loop.
Squaring ten million numbers, four waysfor loop, appending to a list900List comprehension620map() with a lambda700NumPy array, one line15milliseconds on an ordinary laptopThe first three are all Python doing the arithmetic,and they differ by less than a factor of two. Thefourth moves the loop out of Python entirely. Thisis why the fix for slow numeric code is almost nevera better-written loop.

This is the whole reason a later module in this course teaches arrays and dataframes. You do not make a numeric Python loop fast by writing better Python. You move the loop somewhere else. Rewriting it more elegantly buys perhaps 30 per cent; moving it into NumPy buys a factor of fifty.

What this does and does not license

It does not mean Python is a bad choice. For an AI script, almost all the wall-clock time is spent waiting for a network reply or for a GPU that a C library is driving. The Python layer is co-ordinating, not computing, and its overhead disappears into the noise. That is exactly why the field standardised on it.

It does mean you should notice when your own code is doing the arithmetic in a loop over hundreds of thousands of items, because that is the one situation where the language choice shows up in the clock.

The other implementations

CPython, from python.org, is the one you have. There are others:

  • PyPy (free, pypy.org) runs a just-in-time compiler and can be several times faster on pure-Python loops, at the cost of slower startup and imperfect support for some C extensions.
  • CPython itself has been getting faster since 3.11 — the specialising interpreter gained roughly 25 per cent across a broad benchmark suite, and 3.13 added an experimental build without the global lock.

None of these change the picture above. They shrink the constant; the per-object cost is structural.

If you take one thing from this lesson: the difference between fast and slow numeric Python is almost never how the loop is written. It is whether the loop is in Python at all.

The one thing to keep

Python compiles the whole file to bytecode before running any of it, and its slowness comes from every value being a typed heap object, which is why moving a numeric loop into NumPy wins fifty-fold where rewriting it in Python wins thirty per cent.

Before you move on

A script spends 40 seconds looping over 2 million rows doing arithmetic. A developer rewrites the loop more elegantly with comprehensions and helper functions and gets 34 seconds. What does this outcome tell you?

Pick the one you would defend. Nobody sees your answer.

No ads. No data sale. No public scores on people. Ever.

© 2026 Addaly