Code Objects Internals — Core Concepts
What Is a Code Object?
Every time Python compiles a function, a class body, a module, or even a generator expression, it produces a code object. This object is an immutable container that stores everything the interpreter needs to execute that piece of code. It does not store runtime state like variable values — that job belongs to frame objects. The code object is a static description of what to do.
You can access a function’s code object through the __code__ attribute:
def add(a, b):
return a + b
co = add.__code__
Key Attributes
Code objects expose their internals through attributes prefixed with co_:
co_code — The raw bytecode, a bytes object containing the low-level instructions the interpreter steps through. Each instruction is one or more bytes.
co_consts — A tuple of constant values used in the function. For add, this would be (None,) since there are no literal constants beyond the implicit None return.
co_varnames — A tuple of local variable names, in the order they appear. For add, this is ('a', 'b').
co_names — Names used in the function that are not local — global variables, attribute names, imported names.
co_argcount — The number of positional arguments the function accepts. For add, it is 2.
co_stacksize — The maximum depth of the evaluation stack needed to execute the bytecode. The interpreter uses this to pre-allocate the stack.
co_filename and co_firstlineno — Where the code was defined. Tracebacks use these to point you to the right file and line.
How Code Objects Relate to Functions
A function object and a code object are separate things. The function object wraps the code object and adds runtime context: default argument values, closure variables, the global namespace it was defined in. You can even attach a different code object to an existing function (though this is rarely advisable):
def multiply(a, b):
return a * b
# Both functions share different code objects
print(add.__code__ is multiply.__code__) # False
Code Objects Are Immutable
Once created, a code object cannot be modified. Its bytecode, constants, and variable names are all frozen. This immutability is intentional — it means the interpreter can safely share and cache code objects. When you import a module, Python stores the compiled code objects in .pyc files so it can skip recompilation next time.
If you need a modified version, you create a new code object. The code.replace() method (Python 3.8+) lets you produce a copy with specific attributes changed.
Nested Code Objects
Code objects can contain other code objects. If your function defines an inner function or a class, the inner code object appears in the outer one’s co_consts tuple:
def outer():
def inner():
pass
return inner
# outer's co_consts includes inner's code object
for const in outer.__code__.co_consts:
if hasattr(const, 'co_code'):
print(f"Nested code: {const.co_name}") # "inner"
This nesting mirrors the structure of your source — every scope boundary creates a new code object.
A Common Misconception
Code objects are not functions. A function is callable; a code object is not (directly). You need exec() or eval() to run a raw code object, or you wrap it in a function via types.FunctionType. Confusing the two leads to puzzlement when you try to “call” a code object and get a TypeError.
One thing to remember: The code object is the compiled, frozen blueprint of your function. It contains the bytecode instructions, the constants, and the variable layout — everything the interpreter reads at runtime. The function object is just the living wrapper that connects this blueprint to a runtime environment.
See Also
- Python Abstract Syntax Trees How Python reads your code like a recipe before cooking it — the hidden tree structure behind every program.
- Python Bytecode Manipulation How Python secretly translates your code into tiny instructions — and how you can peek at and change those instructions yourself.
- Python Compiler Pipeline The journey your Python code takes from text file to running program — explained like an assembly line.
- Python Frame Objects Why Python keeps a notepad for every running function — and how it remembers where it left off.
- Python Peephole Optimizer How Python quietly tidies up your code behind the scenes — making it faster without you lifting a finger.