Python Code Objects: co_varnames, co_consts, co_names
When Python compiles source code into bytecode, it encapsulates the
executable instructions and execution context into an immutable
structure called a code object (types.CodeType). Key
attributes within this object—specifically co_varnames,
co_consts, and co_names—act as indexed lookup
tables that the Python Virtual Machine (PVM) relies on to execute
operations with high efficiency. Instead of repeatedly resolving
variable and constant names dynamically at runtime via slow string
searches, the PVM uses these tuples to map bytecode instructions
directly to precomputed memory offsets.
How the Python Virtual Machine Uses Lookup Tables
Python bytecode runs on an evaluation loop where instructions operate
on an evaluation stack. Bytecode operations take integer arguments that
represent indices into arrays stored in the code object. When an
instruction like LOAD_CONST 1 executes, the PVM does not
evaluate a value directly; it retrieves the item located at index
1 from the code object's internal constant table.
This design drastically reduces memory overhead through string interning and deduplication, while making lookups an \(O(1)\) array-indexing operation.
co_consts:
Managing Literals and Nested Code
The co_consts tuple stores every literal value defined
within the scope of the code block.
- Contents: Numeric literals, string literals,
booleans,
None, immutable containers (like tuples containing constants), and nested code objects (such as inner functions, lambdas, and class definitions). - Bytecode Instructions: Primarily
LOAD_CONST. - Internal Purpose: Every function begins execution
with
co_constsholding all static data the function needs. For example, Python automatically insertsNoneas the first item inco_constsif a function requires an implicitreturn None. When inner functions or classes are created, their corresponding compiled code objects are stored inside the outer function'sco_conststuple and loaded when the definition line is executed.
co_varnames:
Fast Local Variable Resolution
The co_varnames tuple contains the names of all local
variables used within a code object, starting with the function
arguments.
- Contents: Positional arguments, keyword arguments,
*args,**kwargs, and local variables assigned within the function body. - Bytecode Instructions:
LOAD_FAST,STORE_FAST,DELETE_FAST. - Internal Purpose: Accessing global variables
requires dictionary lookups, which introduce performance overhead. To
solve this, Python optimizes function-level scope using "fast locals."
When a call frame is created, Python allocates a contiguous C array on
the stack sized to match
len(co_varnames). Bytecode instructions likeLOAD_FAST 0directly read the memory offset for index0rather than querying a dictionary.co_varnamespreserves these names primarily for debugging, introspection, and reconstructing tracebacks.
co_names:
Resolving Globals, Built-ins, and Attributes
The co_names tuple contains names referenced in the code
block that are not local variables.
- Contents: Global variables, built-in functions, module names, and attribute names accessed on objects.
- Bytecode Instructions:
LOAD_GLOBAL,STORE_GLOBAL,LOAD_NAME,LOAD_ATTR,STORE_ATTR. - Internal Purpose: Because the PVM cannot predict at
compile time what values an external scope or object attribute will
hold, it cannot assign them fixed array slots like
co_varnames. Instead, Python stores the string name inco_names. When the bytecode encountersLOAD_GLOBAL 0, it fetches the string name at index0ofco_namesand passes it to the dictionary lookup routine for the global and built-in scopes. Similarly,LOAD_ATTR 1takes the string at index1to query an object’s__dict__or descriptor mechanism.
Practical Example
Consider the following function:
import math
def calculate_area(radius):
factor = 2
return factor * math.pi * radiusInspecting its code object (calculate_area.__code__)
reveals how the compiler distributes symbols across these three
tuples:
co_varnamesevaluates to('radius', 'factor'). These are resolved usingLOAD_FASTandSTORE_FASTvia fixed frame offsets.co_constsevaluates to(None, 2). Index0holds the default return valueNone, and index1holds the literal2, retrieved viaLOAD_CONST.co_namesevaluates to('math', 'pi'). The modulemathand its attributepiare resolved dynamically at runtime usingLOAD_GLOBALandLOAD_ATTR.
By separating identifiers into local indices
(co_varnames), literal values (co_consts), and
dynamic symbols (co_names), Python balances static
execution performance with the dynamism of a runtime-evaluated
language.