How compile-time constants are folded, names interned, and local variable slots assigned in the code object.
A code object does not store Python source code as text. It stores compact tables and bytecode instructions that refer to those tables by index.
Three of the most important tables are:
co_consts
co_names
co_varnamesThey separate repeated data from the instruction stream.
For this function:
def f(a):
b = len(a)
return b + 1CPython stores:
constants:
None
1
names:
len
local variables:
a
bThe bytecode instructions then refer to those entries by index.
24.1 Position in the Compilation Pipeline
Constants, names, and locals are assembled during compilation.
AST
↓
symbol table
↓
compiler
↓
instruction stream
↓
constant table
↓
name table
↓
local variable table
↓
code objectThese tables are part of the code object.
The interpreter uses them when executing bytecode.
LOAD_CONST 1
LOAD_GLOBAL 0
LOAD_FAST 0
STORE_FAST 1Each numeric operand indexes into one of the code object’s tables.
24.2 Why Code Objects Use Tables
Bytecode needs to be compact.
Instead of embedding full Python objects or strings directly inside each instruction, CPython stores them once in a table.
Example:
def f():
print("hello")
print("hello")The string "hello" can appear once in co_consts.
The name "print" can appear once in co_names.
The bytecode references them by index.
Conceptually:
co_consts:
0: None
1: "hello"
co_names:
0: "print"
bytecode:
LOAD_GLOBAL 0 print
LOAD_CONST 1 "hello"
CALL
POP_TOP
LOAD_GLOBAL 0 print
LOAD_CONST 1 "hello"
CALL
POP_TOPThis reduces duplication and gives the interpreter stable lookup positions.
24.3 Constants
Constants are literal values and compiled artifacts stored in co_consts.
Common constants include:
None
True
False
integers
floats
complex numbers
strings
bytes
tuples of constants
frozensets of constants
nested code objectsExample:
def f():
return 123, "abc", NoneInspect:
print(f.__code__.co_consts)Typical shape:
(None, 123, 'abc')The tuple returned by the function may itself be constructed from constants, or it may be stored as a constant tuple if the compiler can safely fold it.
24.4 The None Constant
Most code objects include None in co_consts.
Example:
def f():
x = 1Even though the source has no explicit return None, the function returns None implicitly.
The compiler must be able to emit:
LOAD_CONST None
RETURN_VALUEAt module level, CPython also often emits a final RETURN_VALUE with None to finish execution.
24.5 Numeric Constants
Numeric literals usually appear in co_consts.
Example:
def f():
return 10 + 20The AST may contain 10 + 20, but the compiler may fold this into 30.
Inspect:
import dis
def f():
return 10 + 20
print(f.__code__.co_consts)
dis.dis(f)You may see only 30 as a loaded constant.
Constant folding is conservative. CPython can fold expressions that are safe and deterministic at compile time. It cannot fold expressions with runtime effects.
Example:
def f():
return 10 + xx is not known at compile time, so this cannot become a constant.
24.6 String and Bytes Constants
String and bytes literals appear in co_consts.
Example:
def f():
return "hello", b"world"Inspect:
print(f.__code__.co_consts)Adjacent string literals may be concatenated during compilation:
def f():
return "hello" "world"This is a compile-time operation. It does not call string addition at runtime.
The result is one constant:
"helloworld"24.7 Tuple Constants
Tuples containing only constants can be stored as constants.
Example:
def f():
return (1, 2, 3)The compiler may store the entire tuple:
(1, 2, 3)in co_consts.
But if an element is dynamic:
def f(x):
return (1, x, 3)the tuple must be built at runtime.
Compilation pattern:
LOAD_CONST 1
LOAD_FAST x
LOAD_CONST 3
BUILD_TUPLE 3The compiler distinguishes immutable constant containers from runtime-built containers.
24.8 Frozen Set Constants
Set literals are mutable, so a set itself cannot be a constant in bytecode.
But CPython may use frozenset constants for optimized membership tests.
Example:
def is_small(x):
return x in {1, 2, 3}The source uses a set literal. The compiler may compile membership against a frozenset constant because the set is used only for membership testing.
Conceptually:
LOAD_FAST x
LOAD_CONST frozenset({1, 2, 3})
CONTAINS_OPThis avoids rebuilding the set each time the function runs.
The compiler must preserve semantics. This optimization is valid for constants because membership in {1, 2, 3} and frozenset({1, 2, 3}) gives the same result for the relevant operation.
24.9 Nested Code Objects as Constants
Nested functions store their code objects in co_consts.
Example:
def outer():
def inner():
return 1
return innerInspect:
for const in outer.__code__.co_consts:
print(repr(const))You will find a code object for inner.
At runtime, the outer function executes bytecode that loads the nested code object and creates a function object:
LOAD_CONST <code object inner>
MAKE_FUNCTION
STORE_FAST innerThe nested code object is constant compiled data. The function object is created at runtime.
24.10 Name Tables
co_names stores symbolic names used by bytecode operations that are not fast locals or closure variables.
These include:
global names
builtin lookup names
attribute names
imported module names
method names
some class body namesExample:
def f(xs):
return len(xs)Inspect:
print(f.__code__.co_names)Typical shape:
('len',)The bytecode loads len through a name index.
24.11 Globals and Builtins
A name in co_names may refer to a global or builtin at runtime.
Example:
def f(xs):
return len(xs)len is not local. It is loaded using global lookup rules.
Runtime lookup checks:
function globals
then builtinsThe code object does not store the actual builtin function len. It stores the name string "len".
That means changing globals can affect execution:
def f(xs):
return len(xs)
len = lambda x: 999
print(f([1, 2, 3]))Inside that module, len now resolves to the global lambda, not the builtin.
24.12 Attribute Names
Attribute names also live in co_names.
Example:
def f(obj):
return obj.valueInspect:
print(f.__code__.co_names)Typical shape:
('value',)The bytecode uses:
LOAD_FAST obj
LOAD_ATTR valueThe string "value" is stored once in co_names.
This is separate from global lookup. The same table stores name strings used by multiple instruction families.
24.13 Method Names
Method call syntax also uses names.
Example:
def f(obj):
return obj.run()run appears in co_names.
The compiler may emit specialized call-oriented instructions depending on Python version, but the method name still comes from the name table.
Conceptual bytecode:
LOAD_FAST obj
LOAD_METHOD run
CALL 0The name table stores the method name string.
24.14 Import Names
Imports use name tables too.
Example:
def f():
import os
return os.getcwd()The name table may contain:
os
getcwdThe local table contains os if the import is inside a function because import binds a local variable.
This distinction matters:
co_names:
names needed by import and attribute operations
co_varnames:
local binding created by import osImports are assignments from the perspective of local variable layout.
24.15 Local Variables
co_varnames stores fast local variable names.
Example:
def f(a, b):
c = a + b
return cInspect:
print(f.__code__.co_varnames)Typical shape:
('a', 'b', 'c')The frame stores local values in an array-like layout. Bytecode indexes into this layout.
LOAD_FAST 0 a
LOAD_FAST 1 b
STORE_FAST 2 cThis is why local access is faster than global dictionary lookup.
24.16 Parameter Locals
Function parameters appear first in co_varnames.
Example:
def f(a, b, c=0):
d = a + b + c
return dco_varnames usually begins:
('a', 'b', 'c', 'd')The call machinery binds arguments into those fast local slots before the function body begins executing.
Defaults are stored on the function object, not directly in the code object.
print(f.__defaults__)
print(f.__code__.co_varnames)24.17 Positional-Only and Keyword-Only Locals
Code objects store argument counts separately from co_varnames.
Example:
def f(a, b, /, c, *, d):
return a, b, c, dInspect:
code = f.__code__
print(code.co_posonlyargcount)
print(code.co_argcount)
print(code.co_kwonlyargcount)
print(code.co_varnames)The local names are stored in co_varnames, while the counts define how to interpret the leading entries.
Conceptually:
co_varnames:
a, b, c, d
co_posonlyargcount:
2
co_argcount:
3
co_kwonlyargcount:
1The call machinery uses this metadata for argument binding.
24.18 *args and **kwargs
Variable argument names also appear in co_varnames.
Example:
def f(a, *args, **kwargs):
return args, kwargsInspect:
code = f.__code__
print(code.co_varnames)
print(code.co_flags)The co_flags field records that the function accepts variable positional or keyword arguments.
The names args and kwargs are local slots.
24.19 Temporary Values Are Not Named Locals
The evaluation stack holds temporary values.
Example:
def f(a, b, c):
return a + b * cco_varnames contains:
a
b
cIt does not contain temporary intermediate values such as b * c.
That intermediate result lives on the frame’s evaluation stack.
Conceptual stack:
LOAD_FAST a stack: a
LOAD_FAST b stack: a, b
LOAD_FAST c stack: a, b, c
BINARY_OP * stack: a, temp
BINARY_OP + stack: result
RETURN_VALUE stack emptyLocal variables and stack temporaries are separate storage mechanisms.
24.20 Cell Variables
co_cellvars stores locals captured by nested functions.
Example:
def outer():
x = 1
def inner():
return x
return innerInspect:
print(outer.__code__.co_cellvars)Typical result:
('x',)Inside outer, x must live in a cell because inner may access it after outer returns.
The local variable becomes heap-backed closure storage.
24.21 Free Variables
co_freevars stores names captured from enclosing scopes.
Using the same example:
inner = outer()
print(inner.__code__.co_freevars)Typical result:
('x',)Inside inner, x is not a normal local. It is loaded from a closure cell.
Conceptual bytecode:
LOAD_DEREF x
RETURN_VALUEThe code object records the name. The function object carries the actual cell.
24.22 The Locals Dictionary
Inside a normal optimized function, locals