· Hakan Çelik · Python / Metaclass · 2 dk okuma

namespace['attr'] = 1

To see how Python truly processes a class statement: get a namespace with type.__prepare__, execute the body with exec, then build the class with type().

namespace[‘attr’] = 1

In the previous post we built the namespace manually as a plain dict. This time we are reproducing more accurately what Python actually does when it processes a class statement:

import textwrap

class Example:
	attr = 1

	def method(self):
		return "method"

name = "Example"
bases = ()
namespace = type.__prepare__(name, bases)  # >>> {}, default is dict()
# namespace["attr"] = 1
# namespace["method"] = lambda self: "method"

body = textwrap.dedent(
	"""\
	attr = 1

	def method(self):
		return "method"
	"""
)

exec(body, globals(), namespace)
Example = type(name, bases, namespace)  # type: ignore

print(f"{Example.__class__=}")     # <class 'type'>
print(f"{Example().attr=}")        # 1
print(f"{Example().method()=}")    # 'method'

assert isinstance(Example, type)
assert isinstance(Example(), Example)

Three Steps

1. type.__prepare__(name, bases) Returns an empty dict — this namespace will hold all assignments written inside the class body. A custom metaclass can override this step and return something other than a plain dict (see the Logging Namespace post).

2. exec(body, globals(), namespace) Takes the class body as a string and runs it into the namespace dict. This is the exact counterpart of what Python does while processing a class block. Once exec finishes, namespace contains:

{
    'attr': 1,
    'method': <function method at ...>,
    '__module__': '__main__',
    '__qualname__': 'Example',
}

3. type(name, bases, namespace) Creates the class from the populated namespace. The result is identical to writing class Example: ....

Why Does This Matter?

When you write a custom metaclass, the __prepare__, __new__, and __init__ methods correspond exactly to these three steps. While Python hides this process from you, this example lets you see “behind the curtain”.

Back to Blog

Related Posts

View All Posts »
Understanding Python Classes

Understanding Python Classes

Python · 2 dk

In Python, everything is an object and every object has a type — including primitives, functions, and classes themselves. type() and __class__ reveal this relationship.

Run Methods Order In Python

Run Methods Order In Python

Python · 2 dk

Which method runs when in Python metaclasses? The execution order of __prepare__, __new__, __init__, and __call__ during class definition and instance creation.