Of course! The exec() function in Python is a powerful but potentially dangerous tool that executes dynamically created Python code as a string. It's not for classes themselves, but for executing code that defines or uses classes.

Let's break it down into a clear, structured guide.
What is exec()?
The exec() function executes a string or a code object as Python code. Its primary purpose is to run dynamically generated code.
Syntax:
exec(object, globals=None, locals=None)
object: A string containing valid Python code, or a compiled code object.globals(optional): A dictionary representing the global namespace. If provided, code executed byexec()will see this as its global scope. If not, it uses the current global scope.locals(optional): A dictionary representing the local namespace. If provided, it's used for local variables. If not, it defaults to theglobalsdictionary.
Core Concept: exec() and Namespaces
The key to understanding exec() is understanding namespaces. The globals and locals dictionaries define where variables, functions, and classes live.

- Global Namespace: The "top-level" scope of a module. Variables defined here are accessible throughout the module.
- Local Namespace: The scope inside a function. Variables defined here only exist within that function.
When you use exec(), you can control exactly where the results of the executed code are stored.
Example 1: Defining a Class with exec()
This is the most direct answer to your question. You can generate a class definition as a string and then use exec() to make it available in your program.
# 1. Create a string that contains a valid Python class definition
class_definition_string = """
class DynamicPerson:
# This is the constructor, called __init__
def __init__(self, name, age):
self.name = name
self.age = age
print(f"Person object '{self.name}' created!")
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
"""
# 2. Execute the string to define the class in the current global scope
# We use an empty dictionary {} for globals to avoid polluting the main script's globals
# and a dictionary for locals to capture the defined class.
local_scope = {}
exec(class_definition_string, {}, local_scope)
# 3. Check if the class was created
# The class 'DynamicPerson' is now stored in the local_scope dictionary
print(f"Keys in local_scope: {list(local_scope.keys())}")
# 4. Use the newly created class
DynamicPerson = local_scope['DynamicPerson']
# Create an instance of the class
p1 = DynamicPerson("Alice", 30)
# Call a method on the instance
print(p1.greet())
# Create another instance
p2 = DynamicPerson("Bob", 25)
print(p2.greet())
Output:
Person object 'Alice' created!
Keys in local_scope: ['DynamicPerson']
Hello, my name is Alice and I am 30 years old.
Person object 'Bob' created!
Hello, my name is Bob and I am 25 years old.
Why use separate globals and locals dictionaries?
By providing for globals, we ensure that exec() cannot accidentally modify or access variables from our main script's global scope. This is a crucial safety and security practice. The DynamicPerson class is then neatly contained within our local_scope dictionary.

Example 2: Using a Dynamically Defined Class
Here, we'll generate a class name and its attributes dynamically and then create an instance of it.
# 1. Define the dynamic parts of the class
class_name = "Config"
attributes = {
"DEBUG": True,
"PORT": 8000,
"DB_NAME": "my_app_db"
}
# 2. Build the class definition string
code_lines = [f" {key} = {value!r}" for key, value in attributes.items()]
class_body = "\n".join(code_lines)
full_class_string = f"class {class_name}:\n{class_body}"
print("--- Generated Code ---")
print(full_class_string)
print("----------------------\n")
# 3. Execute the code to define the class
# We'll use a dedicated dictionary to hold our new class
config_scope = {}
exec(full_class_string, {}, config_scope)
# 4. Access and use the dynamically created class
Config = config_scope[class_name]
# Now you can use the Config class just like any other
print(f"Config.DEBUG: {Config.DEBUG}")
print(f"Config.PORT: {Config.PORT}")
# It's even accessible as an attribute of the module if you used the main globals
# But this is generally less safe. Let's stick to our safe scope.
# print(f"globals() has 'Config': {'Config' in globals()}") # This would be False
print(f"config_scope has 'Config': {'Config' in config_scope}") # This is True
Output:
--- Generated Code ---
class Config:
DEBUG = True
PORT = 8000
DB_NAME = 'my_app_db'
----------------------
Config.DEBUG: True
Config.PORT: 8000
config_scope has 'Config': True
Example 3: Instantiating a Class Inside exec()
What if you want to not only define a class but also create an instance of it within the exec() block?
# The code we want to execute
code_to_run = """
# Define the class
class Calculator:
def add(self, a, b):
return a + b
# Create an instance of it
# We need a place to store this instance
my_calc_instance = Calculator()
# Use the instance
result = my_calc_instance.add(10, 5)
"""
# Prepare a namespace for the execution
# This dictionary will capture any variables created at the top level
# of the executed code block.
execution_namespace = {}
# Run the code
exec(code_to_run, {}, execution_namespace)
# Check what was created in the namespace
print("Variables created in execution_namespace:")
for key, value in execution_namespace.items():
if not key.startswith('__'): # Ignore dunder methods for clarity
print(f"- {key}: {value} (Type: {type(value).__name__})")
# You can now access the created instance and use it
calculator = execution_namespace['my_calc_instance']
print(f"\nResult from the created calculator: {calculator.add(100, 50)}")
Output:
Variables created in execution_namespace:
- my_calc_instance: <__main__.Calculator object at 0x...> (Type: Calculator)
Result from the created calculator: 150
The Dangers of exec() and Security
⚠️ WARNING: exec() is a major security risk if used with untrusted input.
If you run exec() on a string provided by a user, a malicious user could inject any code they want, including code to delete your files, steal data, or take over your system. This is called Remote Code Execution (RCE).
Bad Example (Vulnerable Code):
# NEVER DO THIS WITH USER INPUT
user_input = input("Enter a command to run: ")
exec(user_input)
A malicious user could type: __import__('os').system('rm -rf /') on a Linux/macOS system to delete all files. (This is an extreme example, but illustrates the risk).
Safe Use Cases:
- Running code generated by your own application logic (as shown in the examples above).
- Creating domain-specific languages (DSLs) or mini-languages for your application.
- Dynamic code generation for testing or metaprogramming.
Alternatives to Consider
Before using exec(), ask if there's a safer, more "Pythonic" way to achieve your goal.
| Use Case | Safer Alternative | Why it's better |
|---|---|---|
| Dynamic Class Creation | type() function |
The type() function is the built-in way to create classes. It's cleaner, faster, and less error-prone than building a string. |
| Dynamic Function Creation | lambda functions or functools.partial |
For simple dynamic functions, lambda is perfect. For more complex ones, creating a function object directly is better than exec(). |
| Evaluating a single expression | eval() function |
eval() only evaluates an expression (it returns a value) and is safer than exec() because it cannot execute statements like import or del. However, it still carries security risks with untrusted input. |
Example: type() for Dynamic Class Creation
The type() function can create a class. The syntax is:
type(name_of_class, (tuple_of_parent_classes,), {dictionary_of_attributes})
class_name = "FastPerson"
parent_classes = (object,) # Good practice to inherit from object
class_attributes = {
'species': 'Homo sapiens',
'greet': lambda self: f"Hi, I'm {self.name}!"
}
# Create the class using type()
FastPerson = type(class_name, parent_classes, class_attributes)
# Use it
fp = FastPerson()
fp.name = "Charlie" # We can add attributes on the fly
print(fp.greet()) # Output: Hi, I'm Charlie!
print(fp.species) # Output: Homo sapiens
Summary
| Feature | Description |
|---|---|
| What it is | A built-in Python function that executes a string as Python code. |
| Primary Use | Running dynamically generated code, such as class or function definitions. |
| Syntax | exec(code_string, globals_dict, locals_dict) |
| Namespaces | The globals and locals dictionaries control where variables from the executed code are stored. Using for globals is a best practice for security. |
| Security | EXTREMELY DANGEROUS with untrusted input. Can lead to Remote Code Execution (RCE). |
| Alternatives | Prefer type() for dynamic class creation and lambda for simple dynamic functions. |
