Hone logo
Hone
Problems

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:

  1. FunctionGenerator Class: Implement a class named FunctionGenerator.

  2. generate_function Method: This method within FunctionGenerator will take a dictionary function_spec as input and return a Python function object.

  3. function_spec Dictionary Structure: The function_spec dictionary 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.
  4. Dynamic Execution: The generated function should execute the code specified in the body and return its result.

Expected Behavior:

  • The generate_function method should return a callable Python function.
  • The returned function should accept the specified arguments.
  • The code in the body should be executed in the context of the generated function, with access to its arguments.
  • If docstring is 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 body that raises exceptions. The generated function should propagate these exceptions.
  • Ensuring that variable names within the body do not unintentionally clash with argument names (though for this challenge, we assume well-behaved body code).

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_spec dictionary will always be valid according to the specified structure.
  • Argument names will be valid Python identifiers.
  • The body code 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 the body code. Consider using exec() 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 body code.
  • The inspect module 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.
Loading editor...
python