Class Body Execution — Core Concepts
The Three Steps of Class Creation
When Python encounters a class statement, it performs three distinct operations:
- Prepare the namespace — Create a dictionary (or custom mapping) to hold the class body’s local variables.
- Execute the class body — Run the indented code as if it were a function body, with the namespace as the local scope.
- Call the metaclass — Pass the class name, bases, and populated namespace to the metaclass (usually
type) to create the class object.
These steps happen at the point where the class statement appears in your code — not lazily, not deferred. It’s immediate.
Step 1: Namespace Preparation
Before executing the class body, Python calls metaclass.__prepare__(name, bases) to get the namespace dictionary. By default, this returns a regular dict.
Custom metaclasses can override __prepare__ to return a different mapping. This is how frameworks control what happens during class body execution — for example, returning an OrderedDict (pre-Python 3.7) or a custom mapping that tracks attribute access.
Step 2: Body Execution
The class body is compiled into a code object and executed with the prepared namespace as locals. This means:
- Variable assignments create entries in the namespace.
- Function definitions (including
defandasync def) add function objects. - Decorator applications happen to functions as they’re defined.
- Any executable code runs immediately — loops, conditions, function calls.
What Runs and When
class Example:
x = 10 # Runs immediately — x added to namespace
print(f"x is {x}") # Runs immediately — prints "x is 10"
def method(self): # Function object created, added to namespace
return self.x # This body does NOT run yet
y = x * 2 # Runs immediately — y is 20
items = [i for i in range(3)] # Runs immediately — [0, 1, 2]
The def method line creates a function object at class-creation time, but the function’s body only runs when someone calls method() later.
Step 3: The type() Call
After the body executes, Python calls:
ClassName = metaclass(name, bases, namespace)
For regular classes, this is type('Example', (object,), {...}). The type.__new__ method:
- Creates the class object.
- Copies the namespace into the class’s
__dict__. - Sets up the MRO.
- Calls
__set_name__on any descriptors. - Calls
__init_subclass__on parent classes.
Timing: Import Time vs. Runtime
This distinction is critical for Python programs:
- Import time: When a module is first imported, all top-level code runs — including all
classstatements. Class bodies execute during import. - Runtime: When methods are called on class instances.
This means side effects in class bodies (database connections, file I/O, network calls) happen at import time, which can cause problems in testing and deployment.
Common Misconception
“A class statement just defines a template.” In many languages (like Java or C#), a class declaration is purely declarative. In Python, it’s imperative — the body is executable code that runs at definition time. This is why you can use loops, conditionals, and function calls inside class bodies.
Practical Implications
Class Attributes Are Shared
class Counter:
count = 0 # Runs once at class creation — shared by all instances
def increment(self):
Counter.count += 1 # Modifies the class attribute
All instances see the same count because it was set once during class body execution.
Mutable Default Gotcha
class Team:
members = [] # Created once during body execution!
def add(self, name):
self.members.append(name) # All instances share this list!
Since members = [] runs once at class creation, every Team instance shares the same list. Fix this by initializing in __init__.
Conditional Class Attributes
import sys
class Config:
if sys.platform == "win32":
path_separator = "\\"
else:
path_separator = "/"
The condition is evaluated once during class creation. The class gets only the matching attribute.
Decorator Order
Class decorators run after the class body executes and the class object is created:
@decorator # Step 4: decorator(ClassName) runs last
class MyClass:
x = 1 # Step 2: body executes
pass
# Step 3: type() creates the class
The decorator receives the fully formed class object and can modify or replace it.
One thing to remember: A Python class statement is executable code. The body runs immediately at definition time, populating a namespace that becomes the class’s attributes. Understanding this timing is key to avoiding side-effect bugs and leveraging metaprogramming.
See Also
- Python Attribute Lookup Chain How Python finds your variables and methods — like checking your pockets, then your bag, then your locker, in a specific order every time.
- Python Bytecode And Interpreter How your .py file turns into tiny instructions the Python interpreter can execute step by step.
- Python Data Model Customization How Python lets your objects behave like built-in types — adding, comparing, looping, and printing, all with special methods.
- Python Garbage Collection See how Python cleans up unreachable objects, especially the tricky ones that point at each other.
- Python Gil Why Python threads can feel stuck in traffic, and how the GIL explains the behavior.