# 23. Code Objects

# 23. Code Objects

A code object is CPython’s compiled representation of executable Python code.

It contains bytecode and metadata. The interpreter can execute it, but the code object itself does not carry runtime state such as globals, default arguments, closure cells, or bound methods.

For this source:

```python
def add(a, b):
    return a + b
```

the function object `add` contains a code object:

```python
code = add.__code__

print(code.co_name)
print(code.co_varnames)
print(code.co_consts)
print(code.co_names)
```

The function object is runtime state. The code object is executable program data.

## 23.1 Position in the Compilation Pipeline

Code objects are the output of compilation.

```text
source text
    ↓
tokenization
    ↓
parsing
    ↓
AST
    ↓
symbol table
    ↓
compiler
    ↓
code object
    ↓
frame execution
```

A code object is the handoff between the compiler and the interpreter.

The compiler emits code objects.

The evaluation loop executes code objects inside frames.

## 23.2 Code Object vs Function Object

A function object wraps a code object.

Example:

```python
def f(x):
    return x + 1
```

At runtime:

```text
function object
    __code__       code object
    __globals__    module globals dictionary
    __defaults__   positional defaults
    __kwdefaults__ keyword-only defaults
    __closure__    closure cells
    __dict__       function attributes
    __name__       function name
    __qualname__   qualified name
```

The code object contains the compiled body.

```text
code object
    bytecode
    constants
    names
    local variable names
    free variable names
    cell variable names
    filename
    line information
    stack size
    flags
```

The same code object can theoretically be used by more than one function object.

```python
import types

def f(x):
    return x + 1

g = types.FunctionType(f.__code__, globals(), "g")

print(g(10))
```

The code is shared. The function wrapper changes the runtime binding.

## 23.3 Code Objects Are Immutable

Code objects are immutable.

Once created, a code object’s bytecode, constants, variable names, flags, and metadata cannot be changed in place.

This matters for safety and runtime design. Multiple functions or frames may refer to the same code object. If code objects were mutable, changing one could affect currently running code.

To modify code, tools create a new code object.

Modern Python exposes a `replace()` method:

```python
def f():
    return 1

new_code = f.__code__.replace(co_name="renamed")
```

This creates a modified copy rather than editing the original object.

## 23.4 Module Code Objects

A module also has a code object.

Example:

```python
src = """
x = 1
y = 2
print(x + y)
"""

code = compile(src, "example.py", "exec")
```

This code object represents top-level execution.

It has no function parameters. Its local namespace is usually the module dictionary.

Inspect:

```python
print(code.co_name)
print(code.co_filename)
print(code.co_consts)
print(code.co_names)
print(code.co_varnames)
```

For module code, `co_name` is often `"<module>"`.

The interpreter executes this code object with globals and locals. Normal imports, script execution, and `exec()` all use module-style code objects.

## 23.5 Expression Code Objects

`compile()` can also produce expression code objects.

Example:

```python
code = compile("1 + 2", "<input>", "eval")
result = eval(code)

print(result)
```

An `eval` code object represents one expression. It returns the expression value.

This differs from `exec` mode:

```python
compile("x = 1", "<input>", "exec")
compile("1 + 2", "<input>", "eval")
```

`exec` mode accepts statements.

`eval` mode accepts only an expression.

The mode changes both the grammar start point and the generated code object behavior.

## 23.6 Interactive Code Objects

Interactive mode uses `"single"` compilation.

Example:

```python
code = compile("1 + 2", "<stdin>", "single")
exec(code)
```

In interactive mode, expression results may be printed automatically by the display hook.

This is why the REPL behaves differently from script execution.

```text
exec mode:
    execute statements normally

eval mode:
    return expression value

single mode:
    behave like interactive input
```

The code object records enough information for the interpreter to run the selected mode correctly.

## 23.7 Nested Code Objects

Nested executable constructs produce nested code objects.

Example:

```python
def outer(x):
    def inner(y):
        return x + y
    return inner
```

The module code object contains the code object for `outer` in `co_consts`.

The `outer` code object contains the code object for `inner` in its own `co_consts`.

Inspect:

```python
def outer(x):
    def inner(y):
        return x + y
    return inner

outer_code = outer.__code__
print(outer_code.co_consts)

for const in outer_code.co_consts:
    if isinstance(const, type(outer_code)):
        print("nested code:", const.co_name)
```

Nested code objects are constants because they are compiled data embedded in the enclosing code object.

At runtime, `MAKE_FUNCTION` creates function objects from those code objects.

## 23.8 `co_code`

`co_code` stores bytecode bytes.

Example:

```python
def f(a, b):
    return a + b

print(f.__code__.co_code)
```

Raw `co_code` is not pleasant to read directly. Use `dis`:

```python
import dis

dis.dis(f)
```

Bytecode is an instruction stream for CPython’s virtual machine.

Each instruction has an opcode and possibly an argument. The exact encoding changes across versions, so tools should use `dis` rather than hard-coding byte offsets.

## 23.9 `co_consts`

`co_consts` stores constants referenced by bytecode.

Example:

```python
def f():
    return 1, "x", None
```

Inspect:

```python
print(f.__code__.co_consts)
```

Typical contents:

```text
(None, 1, 'x')
```

Constants may include:

```text
None
booleans
numbers
strings
bytes
tuples of constants
frozensets
nested code objects
```

The compiler deduplicates some constants within a code object.

Bytecode instructions load constants by index:

```text
LOAD_CONST 1
```

means “load `co_consts[1]`.”

## 23.10 `co_names`

`co_names` stores names used for global lookup, attribute lookup, imports, and similar operations.

Example:

```python
def f(xs):
    return len(xs)
```

Inspect:

```python
print(f.__code__.co_names)
```

Likely output:

```text
('len',)
```

The bytecode uses an index into `co_names`:

```text
LOAD_GLOBAL 0
```

meaning “load the global or builtin name `co_names[0]`.”

Example with attribute access:

```python
def f(obj):
    return obj.value
```

`value` appears in `co_names` because attribute names are stored there too.

## 23.11 `co_varnames`

`co_varnames` stores local variable names.

Example:

```python
def f(a, b):
    c = a + b
    return c
```

Inspect:

```python
print(f.__code__.co_varnames)
```

Typical output:

```text
('a', 'b', 'c')
```

Fast local bytecode uses indexes into this tuple.

```text
LOAD_FAST 0    a
LOAD_FAST 1    b
STORE_FAST 2   c
```

This array-indexed local access is much faster than dictionary lookup.

## 23.12 `co_freevars` and `co_cellvars`

Closures use two code object fields.

| Field         | Meaning                                  |
| ------------- | ---------------------------------------- |
| `co_cellvars` | Locals captured by nested scopes         |
| `co_freevars` | Variables captured from enclosing scopes |

Example:

```python
def outer():
    x = 1

    def inner():
        return x

    return inner
```

Inspect:

```python
print(outer.__code__.co_cellvars)

inner = outer()
print(inner.__code__.co_freevars)
```

Expected shape:

```text
('x',)
('x',)
```

For `outer`, `x` is a cell variable because nested code needs it.

For `inner`, `x` is a free variable because it comes from an enclosing scope.

## 23.13 Closure Cells Are Not Stored in Code Objects

A code object records which free variables it needs. It does not store the actual captured values.

The captured values live in closure cells attached to the function object.

Example:

```python
def make_reader(value):
    def read():
        return value
    return read

f = make_reader(42)

print(f.__code__.co_freevars)
print(f.__closure__)
print(f.__closure__[0].cell_contents)
```

The code object says:

```text
this function needs a free variable named value
```

The function object supplies:

```text
the actual cell containing 42
```

This separation lets the same nested code object be reused with different captured values.

## 23.14 `co_argcount` and Argument Metadata

Code objects store argument counts.

Important fields include:

```text
co_argcount
co_posonlyargcount
co_kwonlyargcount
co_varnames
co_flags
```

Example:

```python
def f(a, b, /, c, *, d):
    return a, b, c, d
```

Inspect:

```python
code = f.__code__

print(code.co_argcount)
print(code.co_posonlyargcount)
print(code.co_kwonlyargcount)
print(code.co_varnames)
```

These fields help the function call machinery bind arguments to local variable slots.

Defaults are not stored in the code object. They live on the function object:

```python
def f(x=1):
    return x

print(f.__defaults__)
print(f.__code__.co_consts)
```

The default value belongs to the function object because defaults are evaluated at function definition time.

## 23.15 `co_flags`

`co_flags` stores execution flags.

Flags describe properties such as:

```text
has *args
has **kwargs
is generator
is coroutine
is async generator
uses nested scopes
future flags
```

Example:

```python
def normal():
    return 1

def gen():
    yield 1

async def coro():
    return 1
```

Inspect:

```python
print(normal.__code__.co_flags)
print(gen.__code__.co_flags)
print(coro.__code__.co_flags)
```

The runtime uses these flags to decide what object to create when a function is called.

A generator function returns a generator object.

A coroutine function returns a coroutine object.

A normal function executes normally and returns a value.

## 23.16 `co_stacksize`

`co_stacksize` records the maximum evaluation stack depth needed by the code object.

Example:

```python
def f(a, b, c):
    return a + b * c
```

The compiler computes stack usage from bytecode stack effects.

Conceptually:

```text
LOAD_FAST a       stack depth 1
LOAD_FAST b       stack depth 2
LOAD_FAST c       stack depth 3
BINARY_OP *       stack depth 2
BINARY_OP +       stack depth 1
RETURN_VALUE      stack depth 0
```

Maximum depth: 3.

The frame uses `co_stacksize` to allocate enough stack storage.

## 23.17 Source Metadata

Code objects store source metadata.

Important fields include:

```text
co_filename
co_name
co_qualname
co_firstlineno
line table data
position table data
```

Example:

```python
def f():
    x = 1
    return x

code = f.__code__

print(code.co_filename)
print(code.co_name)
print(code.co_qualname)
print(code.co_firstlineno)
```

This metadata supports:

```text
tracebacks
debuggers
profilers
coverage tools
inspection
warnings
error locations
```

Without source metadata, Python execution would still be possible, but diagnostics would be much worse.

## 23.18 Line Tables and Positions

Code objects map bytecode offsets back to source positions.

You can inspect positions:

```python
def f(x):
    return x + 1

for item in f.__code__.co_positions():
    print(item)
```

This source mapping supports precise tracebacks and debugging.

Older CPython versions used different line number table formats. Modern versions expose richer position information, including column offsets.

Tools should prefer public methods rather than directly parsing private binary tables.

## 23.19 Exception Tables

Modern CPython code objects include exception table information.

Exception tables describe which bytecode ranges are protected by exception handlers.

Example:

```python
def f():
    try:
        risky()
    except ValueError:
        recover()
```

The bytecode is not enough by itself. The interpreter also needs metadata such as:

```text
protected instruction range
handler target
stack depth restoration information
handler kind
```

This metadata lets CPython implement `try`, `except`, `finally`, and related control flow.

## 23.20 Code Object Creation from `compile()`

The `compile()` built-in creates code objects.

Example:

```python
code = compile("x = 1\n", "<input>", "exec")

ns = {}
exec(code, ns)

print(ns["x"])
```

For expressions:

```python
code = compile("1 + 2", "<input>", "eval")

print(eval(code))
```

For AST input:

```python
import ast

tree = ast.parse("x = 1\n")
code = compile(tree, "<ast>", "exec")
```

`compile()` runs the same broad pipeline used for files:

```text
source or AST
    ↓
validation
    ↓
symbol analysis
    ↓
bytecode generation
    ↓
code object
```

## 23.21 Executing Code Objects

Code objects can be executed with `exec()` or `eval()`.

Example:

```python
code = compile("x = 10\n", "<input>", "exec")

globals_dict = {}
locals_dict = {}

exec(code, globals_dict, locals_dict)

print(locals_dict["x"])
```

`exec()` supplies runtime namespaces.

The code object itself does not contain those namespaces.

For expression code:

```python
code = compile("x + 1", "<input>", "eval")

print(eval(code, {"x": 41}))
```

The same code object can execute with different globals.

## 23.22 Code Objects and Frames

A frame is a running instance of a code object.

Code object:

```text
immutable compiled instructions
```

Frame:

```text
current execution state
instruction pointer
local variables
evaluation stack
block state
globals
builtins
exception state
```

Example:

```python
def f(x):
    y = x + 1
    return y
```

Each call to `f` creates or uses a frame executing `f.__code__`.

Multiple calls use the same code object but different frame state.

```text
f.__code__
    shared by all calls

frame for f(1)
    x = 1
    y = 2

frame for f(10)
    x = 10
    y = 11
```

## 23.23 Code Objects and `marshal`

CPython can serialize code objects with `marshal`.

Compiled `.pyc` files contain marshalled code objects plus header metadata.

This is implementation-specific. The `marshal` format is not a stable general-purpose serialization format.

Practical rule:

```text
use pickle or another format for application data
use marshal only for CPython internals or closely related tooling
```

When Python imports a module, CPython may load a cached `.pyc` file, read the code object, and execute it instead of recompiling source.

## 23.24 Code Objects in `.pyc` Files

A `.pyc` file stores compiled bytecode cache data.

Conceptually:

```text
.pyc file
    header
        magic number
        invalidation metadata
    marshalled module code object
```

The module code object may contain nested function and class body code objects in `co_consts`.

The bytecode cache speeds startup by avoiding repeated parsing and compilation when source has not changed.

But `.pyc` files are version-specific. Bytecode and marshal formats can change across CPython versions.

## 23.25 Code Object Security Boundaries

Code objects are executable data.

Running a code object is equivalent to running code.

Example:

```python
code = compile("import os; os.remove('file.txt')", "<input>", "exec")
exec(code)
```

The code object does not become safe because it has already been compiled.

Security-sensitive systems should not execute untrusted code objects, untrusted source, or untrusted marshalled bytecode.

Compilation is not sandboxing.

## 23.26 Code Object Introspection

Code objects are useful for introspection.

Example:

```python
def f(a, b=1):
    c = a + b
    return c

code = f.__code__

for name in [
    "co_argcount",
    "co_posonlyargcount",
    "co_kwonlyargcount",
    "co_nlocals",
    "co_stacksize",
    "co_flags",
    "co_consts",
    "co_names",
    "co_varnames",
    "co_freevars",
    "co_cellvars",
]:
    print(name, getattr(code, name))
```

This supports tools such as:

```text
debuggers
profilers
coverage tools
tracers
decorators
test frameworks
bytecode inspectors
static analysis helpers
```

## 23.27 Code Object Replacement

Code objects can be copied with modifications using `replace()`.

Example:

```python
def f():
    return 1

new_code = f.__code__.replace(co_name="g")
```

This is useful for advanced tools.

But changing code object internals can easily violate assumptions. For example, bytecode, constants, names, stack size, flags, and exception tables must remain consistent.

A broken code object can crash tools, raise confusing errors, or behave incorrectly.

Use `replace()` for metadata edits or carefully validated bytecode work.

## 23.28 Code Objects Are Version-Specific

Code object fields and bytecode details change across Python versions.

Examples of version-sensitive areas:

```text
opcode names
opcode arguments
inline cache layout
exception table format
line table format
code object constructor signature
optimization behavior
```

Robust tools should use public APIs:

```text
dis
inspect
types.CodeType.replace
co_positions()
co_lines()
ast
compile
```

Avoid assuming that raw bytecode layout remains stable.

## 23.29 CPython Source Areas

Important CPython source files include:

```text
Include/cpython/code.h
Objects/codeobject.c
Python/compile.c
Python/assemble.c
Python/flowgraph.c
Python/marshal.c
Lib/dis.py
Lib/inspect.py
Lib/types.py
```

Conceptual roles:

| Area           | Role                               |
| -------------- | ---------------------------------- |
| `code.h`       | Code object structure definitions  |
| `codeobject.c` | Code object creation and behavior  |
| `compile.c`    | AST to instruction generation      |
| `assemble.c`   | Final code object assembly         |
| `flowgraph.c`  | Control-flow graph processing      |
| `marshal.c`    | Serialization for bytecode caches  |
| `dis.py`       | Human-readable bytecode inspection |

## 23.30 Minimal Mental Model

Use this model:

```text
A code object is immutable compiled Python code.
It contains bytecode plus metadata.
A function object wraps a code object with runtime context.
A frame executes a code object.
Nested functions, lambdas, classes, comprehensions, and generators have nested code objects.
Constants, names, locals, free variables, and cell variables are stored in code object tables.
The interpreter uses the code object to allocate frames and run bytecode.
```

Code objects are the compiled artifact that connects CPython’s compiler to its virtual machine.

