What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
When Python runs your code, it does not run text directly. The source is organized into code blocks, each block runs in an execution frame, names are bindings that refer to objects, and expressions are evaluated in an order the language specifies. In CPython, the reference implementation most people use, the compiled form is bytecode, which a bytecode interpreter executes. Most confusion comes from mixing those layers together. This guide separates them so you can tell which parts are guaranteed by the language and which depend on the implementation.
How to read the labels in this guide
Every diagram and claim below falls into one of four categories. The reference pages cited here are the Python Language Reference and its supporting pages, and each one is tied to a specific documentation version.
| Label | What it means | Where it is defined |
|---|---|---|
| Language guarantee | Required of any conforming Python implementation. | Execution model and expressions chapters of the Python 3.14 documentation. |
| CPython implementation detail | True of the CPython interpreter; other implementations may differ. | Stated as such in the data model reference (Python 3.13 documentation), and the glossary (Python 3.11 documentation) for the bytecode definition. |
| Conceptual model | A useful way to organize the runtime; implementations need not build these layers as separate structures. | Execution model chapter, Python 3.14.8 documentation. |
| Version-specific detail | Depends on a particular release, such as bytecode instruction sequences. | Must be checked against the version you run. |
The examples in this guide were written against the language rules described in these references. They do not depend on a particular CPython build, but bytecode details do, which is why that section is kept separate.
The path from source text to execution
The following diagram shows the order in which the pieces relate. It is a teaching model, not a memory map.
#1 Best Overall
SOURCE TEXT [language guarantee]
| compiled into code blocks
v
CODE BLOCK (module, function body, class body) [language guarantee]
| runs in
v
EXECUTION FRAME (per run of a block; [language guarantee: role]
holds bookkeeping and controls flow)
| name lookup follows scope rules
v
NAMES ----refer to----> OBJECTS [language guarantee]
(identity, type, value)
| expressions evaluated in specified order
v
BYTECODE -> bytecode interpreter loop [CPython implementation detail]
|
v
PROCESS > PYTHON RUNTIME > INTERPRETER > THREAD > THREAD STATE
[conceptual model]
Read the diagram top to bottom for the common path, but keep in mind that name lookup and evaluation happen while a block is running, not in a separate stage before it.
Code blocks: what your source becomes
The execution model defines a code block as a unit of program text that is run as one piece. Modules, function bodies, and class definitions are code blocks. Scripts and interactive commands are also treated as blocks. These are the forms you will see most often:
Module blocks
A module is the top level of a file. When you run a script, its top-level statements form a module-level block. When you import a file, its top-level statements run as a module block the first time the module is imported.
Recommended Free Tools
Function body blocks
The indented body after def is a block. Its statements do not run when the def line executes; they run when the function is called.
def greet(name):
message = 'Hello, ' + name # runs on each call, not at definition
return message
print(greet('Ada'))
Class definition blocks
The body of a class statement is a block too. It runs once, when the class statement executes, and it has its own scope rules, covered in the name lookup section below.
Rank #2
Scripts and interactive commands
Each statement you type at the interactive prompt, and each file you run as a script, is treated as a block. For learning the model, you can treat a script as a module block.
Execution frames: where a block runs
The execution model says a code block is executed in an execution frame. A frame carries administrative information the interpreter needs while the block runs, and it determines how execution continues, for example what runs next after a statement finishes. Each call to a function runs its body in a new frame, and the frame exists for the duration of that run.
Treat the frame as the context in which a block’s names are looked up and its statements execute. Do not picture it as a fixed-size box sitting at a particular place in memory. The reference describes what a frame does, not how it is laid out, and layout is an implementation matter.
Names and objects
The name binding rules state that names refer to objects. This is the most important idea in the model. A name is a label in a namespace, and the object is what the label points to.
Binding, not copying
A binding operation associates a name with an object. The reference lists several common binding operations: parameters, function and class definitions, assignment targets, import statements, and others. Assignment is one of them, but assignment does not automatically copy the object on the right-hand side. What happens depends on the expression that produced the value and the binding operation involved.
a = [1, 2]
b = a # b is bound to the same list object a refers to
b.append(3)
print(a) # [1, 2, 3]
a = [9] # a now refers to a different object
print(b) # [1, 2, 3]
The second assignment rebinds a. It does not change the list that b still refers to. The list was never copied, so the two names shared it until one of them was rebound.
Identity, type, and value
The data model reference states that all data in a Python program is represented by objects or by relations between objects, and that every object has an identity, a type, and a value. Identity is stable for an object’s lifetime. The is operator tests whether two names refer to the same object. After b = a above, a is b evaluates to True.
What id() means
The data model describes id() as returning an integer that represents an object’s identity. The same reference labels the statement that this integer is the object’s memory address as a CPython implementation detail. Use is and id() to compare identity within a running program, and do not rely on any particular numeric value.
Name lookup: why a later assignment changes an earlier read
Name resolution follows scope rules, and the rules are decided from the source of a block, not from what has run so far. The execution model states that a name bound anywhere in a function body makes that name local to the whole body, unless it is declared global or nonlocal. This applies even before the line that binds it has run.
count = 10
def report():
print(count) # UnboundLocalError: count is local to report()
count = 20
report()
A reader might expect the first print to see the module-level value of 10. It does not. Because count = 20 binds the name anywhere in the function, count is local throughout it, and reading it before assignment raises UnboundLocalError.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →To write to the module-level name, declare it:
count = 10
def report():
global count
print(count) # 10
count = 20 # rebinds the module-level name
report()
print(count) # 20
global and nonlocal
global makes a name refer to the module-level namespace. nonlocal makes a name refer to the nearest enclosing function scope that binds it. Use nonlocal only inside a nested function, and only for a name the enclosing function already binds.
Class bodies are a special case
Names defined in a class body are limited to that class block. They are not visible as plain names inside the methods defined in the class body. Methods reach class attributes through an instance or the class itself, not through bare names. The execution model also contains special rules for exec() and eval(), which execute code from strings or objects. Those rules are beyond this guide, so consult the execution model section on dynamic execution when you need them.
Evaluation order comes from the expression rules
The expressions chapter (Python 3.14.7 documentation) is the authority for evaluation order. It states that Python evaluates expressions from left to right, and it gives a specific exception for assignment: the right-hand side is evaluated before the left-hand side. This is a language guarantee, so you can rely on it in any conforming implementation.
def left():
print('left')
return 1
def right():
print('right')
return 2
total = left() + right() # prints left, then right
def target_index():
print('subscript evaluated')
return 0
def new_value():
print('right-hand side evaluated')
return 5
data = [0]
data[target_index()] = new_value()
# prints: right-hand side evaluated
# subscript evaluated
The second example is the one that surprises people. The target expression data[target_index()] is evaluated after the value expression, because the expressions chapter specifies that the right-hand side of an assignment is evaluated first.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Bytecode: the CPython view
Label: CPython implementation view, not a language contract. The glossary entry (Python 3.11.17 documentation) states that Python source is compiled to bytecode, the internal representation of a program in the CPython interpreter. The bytecode is what the interpreter loop executes after the source has been compiled.
Best Value
Bytecode is useful for understanding performance and for debugging odd behavior, but it is not the same across all versions and implementations. The instruction names and sequences change between releases, and the definition above is the only part you can rely on in general. To see the bytecode for the interpreter you actually run, use the standard library dis module on that installation rather than copying a listing from a different version.
The conceptual runtime
The execution model sketches a set of layers around execution. These layers help you place the interpreter in context, but the reference is explicit that an implementation need not implement them distinctly or concretely. It also distinguishes the full-featured runtime called an interpreter from the bytecode interpreter that executes compiled code.
| Conceptual layer | Role in the model | Status |
|---|---|---|
| Host machine | The physical or virtual machine running Python. | Conceptual |
| Process | The operating-system process that hosts the Python runtime. | Conceptual |
| Python global runtime | State shared across the program’s Python execution. | Conceptual |
| Interpreter | The full-featured runtime that holds execution state for Python code. | Conceptual, as the model defines it |
| Thread and thread state | The thread executing Python code and the state it carries. | Conceptual; the thread-state details are implementation-dependent |
Do not assume that every layer maps to a separate struct, file, or object in your interpreter. Use the table to answer where execution happens, not how memory is organized.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteKeeping the model straight in practice
- When a name seems to change unexpectedly, ask which object it refers to and whether another name was bound to the same object.
- When a read raises
UnboundLocalError, look for an assignment to the same name anywhere in that function body. - When the order of side effects looks wrong, check the expressions chapter for the rule that applies, rather than guessing from how the line reads.
- When you need bytecode, check the Python version first, then inspect that interpreter’s output.
Further reading
For a deeper follow-on that covers Python internals down to bytecode, No Starch Press describes Serious Python by Julien Danjou as addressing those topics; see nostarch.com/seriouspython. Treat it as a next step after this guide rather than a replacement for the reference pages above.
Primary sources used in this guide: Python 3.14.8 execution model, Python 3.13.16 data model, Python 3.14.7 expressions, and Python 3.11.17 glossary.
The Bottom Line
Python’s behavior is easiest to predict when you keep three things separate: names point to objects, scope is decided from the source of each block, and evaluation order is fixed by the language. Bytecode and the runtime layers are useful for understanding CPython, but they are implementation views and should be checked against the version you run.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.

