Python Code Generator: Dynamic Function Creator
This challenge tasks you with building a Python program that dynamically generates Python functions based on a given specification. This is a powerful technique useful for creating boilerplate code, simplifying repetitive tasks, and building domain-specific languages.
Problem Description
Your goal is to create a Python class FunctionGenerator that can generate new Python functions on the fly. The generator should accept a dictionary defining the structure of the function to be created, including its name, arguments, and the code to be executed within its body.
Key Requirements:
-
FunctionGeneratorClass: Implement a class namedFunctionGenerator. -
generate_functionMethod: This method withinFunctionGeneratorwill take a dictionaryfunction_specas input and return a Python function object. -
function_specDictionary Structure: Thefunction_specdictionary must contain the following keys:name(string): The name of the function to be generated.args(list of strings): A list of argument names for the function.body(string): A multi-line string representing the Python code to be executed inside the function. This code can use f-strings for dynamic content, referring to arguments by their names.docstring(string, optional): A string for the function's docstring.
-
Dynamic Execution: The generated function should execute the code specified in the
bodyand return its result.
Expected Behavior:
- The
generate_functionmethod should return a callable Python function. - The returned function should accept the specified arguments.
- The code in the
bodyshould be executed in the context of the generated function, with access to its arguments. - If
docstringis provided, the generated function should have it.
Edge Cases:
- Functions with no arguments.
- Functions with empty bodies (though this is generally not useful).
- Code in the
bodythat raises exceptions. The generated function should propagate these exceptions. - Ensuring that variable names within the
bodydo not unintentionally clash with argument names (though for this challenge, we assume well-behavedbodycode).
Examples
Example 1:
Input:
function_spec_1 = {
"name": "greet",
"args": ["name"],
"body": "return f'Hello, {name}!'",
"docstring": "Generates a greeting message."
}
generator = FunctionGenerator()
generated_greet_func = generator.generate_function(function_spec_1)
# How to use the generated function
output_1 = generated_greet_func("Alice")
print(output_1)
print(generated_greet_func.__doc__)
Output:
Hello, Alice!
Generates a greeting message.
Explanation:
The generate_function method creates a function named greet that takes one argument name. The body executes an f-string to construct and return a greeting. The docstring is also correctly assigned.
Example 2:
Input:
function_spec_2 = {
"name": "add_numbers",
"args": ["a", "b"],
"body": """
result = a + b
return result
"""
}
generator = FunctionGenerator()
generated_add_func = generator.generate_function(function_spec_2)
# How to use the generated function
output_2 = generated_add_func(5, 3)
print(output_2)
print(generated_add_func.__doc__) # Should be None or empty if not provided
Output:
8
None
Explanation:
This example shows a function with multiple arguments and a multi-line body. The code correctly adds the two input numbers and returns the sum. No docstring was provided, so __doc__ is None.
Example 3:
Input:
function_spec_3 = {
"name": "calculate_area",
"args": ["length", "width"],
"body": "return length * width"
}
generator = FunctionGenerator()
generated_area_func = generator.generate_function(function_spec_3)
# How to use the generated function
output_3 = generated_area_func(10, 5)
print(output_3)
Output:
50
Explanation: A simple function to calculate the area of a rectangle. Demonstrates a straightforward calculation within the generated function.
Constraints
- The
function_specdictionary will always be valid according to the specified structure. - Argument names will be valid Python identifiers.
- The
bodycode will be syntactically correct Python. - The generated function's execution time will be within reasonable limits for typical Python code.
- You should not use
eval()to execute thebodycode. Consider usingexec()or other more controlled methods.
Notes
- Think about how to dynamically construct the function definition itself. Python's
exec()function can be used to execute Python code from strings. - Consider how to capture and return the output of the
bodycode. - The
inspectmodule might be helpful for introspection or verification, but it's not strictly required for generating the function. - The core challenge lies in programmatically creating a function object.