0
# Dynamic Function Creation
1
2
Core functionality for creating functions dynamically from signature specifications. This capability enables runtime generation of functions with precise signature control, proper introspection support, and comprehensive metadata management.
3
4
## Capabilities
5
6
### Function Creation from Signatures
7
8
Creates functions dynamically from string signatures or Signature objects, with full control over metadata and behavior.
9
10
```python { .api }
11
def create_function(
12
func_signature: Union[str, Signature],
13
func_impl: Callable[[Any], Any],
14
func_name: str = None,
15
inject_as_first_arg: bool = False,
16
add_source: bool = True,
17
add_impl: bool = True,
18
doc: str = None,
19
qualname: str = None,
20
co_name: str = None,
21
module_name: str = None,
22
**attrs
23
) -> FunctionType:
24
"""
25
Creates a function with signature func_signature that calls func_impl.
26
27
Parameters:
28
- func_signature: Union[str, Signature]
29
Function signature specification. Can be:
30
- String without 'def': "foo(a, b: int, *args, **kwargs)" or "(a, b: int)"
31
- Signature object from inspect.signature() or manually created
32
- func_impl: Callable[[Any], Any]
33
Implementation function that will be called by generated function
34
- func_name: str, optional
35
Override for __name__ and __qualname__ attributes
36
- inject_as_first_arg: bool, default False
37
If True, inject created function as first positional argument to func_impl
38
- add_source: bool, default True
39
Add __source__ attribute containing generated function source code
40
- add_impl: bool, default True
41
Add __func_impl__ attribute pointing to func_impl
42
- doc: str, optional
43
Docstring for generated function. Defaults to func_impl.__doc__
44
- qualname: str, optional
45
Qualified name for generated function
46
- co_name: str, optional
47
Name for compiled code object
48
- module_name: str, optional
49
Module name for generated function. Defaults to func_impl.__module__
50
- **attrs: dict
51
Additional attributes to set on generated function
52
53
Returns:
54
FunctionType: Generated function with specified signature
55
56
Raises:
57
TypeError: If func_signature has invalid type
58
SyntaxError: If signature string is malformed
59
ValueError: If co_name is invalid
60
"""
61
```
62
63
### Usage Examples
64
65
#### Basic Function Creation from String
66
67
```python
68
from makefun import create_function
69
70
def my_impl(name, age, city="Unknown"):
71
return f"{name} ({age}) from {city}"
72
73
# Create function with specific signature
74
greet = create_function("greet(person_name: str, person_age: int, location: str = 'Unknown')",
75
my_impl)
76
77
print(greet("Alice", 25)) # "Alice (25) from Unknown"
78
print(greet("Bob", 30, "New York")) # "Bob (30) from New York"
79
```
80
81
#### Function Creation from Signature Object
82
83
```python
84
from makefun import create_function
85
from inspect import signature, Signature, Parameter
86
87
def calculator(operation, x, y):
88
operations = {"add": x + y, "sub": x - y, "mul": x * y}
89
return operations.get(operation, "Unknown operation")
90
91
# Create signature object manually
92
params = [
93
Parameter('op', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
94
Parameter('a', Parameter.POSITIONAL_OR_KEYWORD, annotation=float),
95
Parameter('b', Parameter.POSITIONAL_OR_KEYWORD, annotation=float)
96
]
97
sig = Signature(parameters=params, return_annotation=float)
98
99
# Generate function with Signature object
100
calc = create_function(sig, calculator, func_name="calculate")
101
print(calc("add", 5.0, 3.0)) # 8.0
102
```
103
104
#### Advanced Metadata Control
105
106
```python
107
from makefun import create_function
108
109
def internal_handler(*args, **kwargs):
110
return f"Processed: {args}, {kwargs}"
111
112
# Create function with extensive metadata customization
113
processor = create_function(
114
"process_data(data: list, options: dict = None, verbose: bool = False)",
115
internal_handler,
116
func_name="process_data",
117
doc="Process data with optional configuration and verbosity control.",
118
qualname="DataProcessor.process_data",
119
module_name="data_processing",
120
add_source=True,
121
add_impl=True,
122
version="1.0",
123
author="Data Team"
124
)
125
126
print(processor.__name__) # "process_data"
127
print(processor.__doc__) # "Process data with optional configuration..."
128
print(processor.__module__) # "data_processing"
129
print(processor.version) # "1.0"
130
print(processor.author) # "Data Team"
131
```
132
133
#### Generator and Coroutine Support
134
135
```python
136
from makefun import create_function
137
import asyncio
138
139
def my_generator(*args, **kwargs):
140
for i in range(3):
141
yield f"Item {i}: {args}, {kwargs}"
142
143
async def my_coroutine(*args, **kwargs):
144
await asyncio.sleep(0.1)
145
return f"Async result: {args}, {kwargs}"
146
147
# Create generator function
148
gen_func = create_function("generate_items(count: int, prefix: str)", my_generator)
149
for item in gen_func(3, "test"):
150
print(item)
151
152
# Create coroutine function
153
async_func = create_function("fetch_data(url: str, timeout: int = 30)", my_coroutine)
154
result = asyncio.run(async_func("https://api.example.com", 60))
155
print(result)
156
```
157
158
#### Lambda Function Generation
159
160
```python
161
from makefun import create_function
162
163
def simple_impl(x, y):
164
return x + y
165
166
# Function name not valid identifier -> creates lambda
167
lambda_func = create_function("123invalid(x, y)", simple_impl)
168
print(lambda_func.__name__) # "<lambda>"
169
170
# Explicit lambda creation
171
lambda_func2 = create_function("(x: int, y: int)", simple_impl, co_name="<lambda>")
172
print(lambda_func2.__name__) # None (lambda functions have no __name__)
173
```
174
175
### Function Argument Handling
176
177
The generated functions automatically handle argument passing to the implementation function:
178
179
- **Keyword Arguments**: Most arguments are passed as keywords when possible for maximum flexibility
180
- **Positional-Only**: Arguments marked as positional-only are passed positionally
181
- **Var-Positional**: `*args` arguments are passed as positional arguments
182
- **Var-Keyword**: `**kwargs` arguments are passed as keyword arguments
183
184
### Signature String Format
185
186
Signature strings support the full Python function signature syntax:
187
188
```python
189
# Basic parameters
190
"func(a, b, c)"
191
192
# Type annotations
193
"func(a: int, b: str, c: float)"
194
195
# Default values
196
"func(a: int, b: str = 'default', c: float = 1.0)"
197
198
# Var-positional and var-keyword
199
"func(a: int, *args, **kwargs)"
200
201
# Keyword-only parameters (Python 3+)
202
"func(a: int, *, b: str, c: float = 1.0)"
203
204
# Positional-only parameters (Python 3.8+)
205
"func(a: int, b: str, /, c: float)"
206
207
# Return type annotation
208
"func(a: int, b: str) -> str"
209
210
# Complex example
211
"process(data: list, /, mode: str, *extra, timeout: float = 30.0, **options) -> dict"
212
```
213
214
### Error Handling
215
216
Common error scenarios and their handling:
217
218
```python
219
from makefun import create_function
220
221
# Invalid signature format
222
try:
223
create_function("invalid syntax here", lambda: None)
224
except SyntaxError as e:
225
print(f"Signature error: {e}")
226
227
# Invalid function name
228
try:
229
create_function("func(x)", lambda x: x, co_name="123invalid")
230
except ValueError as e:
231
print(f"Name error: {e}")
232
233
# Type mismatch
234
try:
235
create_function(123, lambda: None) # Should be str or Signature
236
except TypeError as e:
237
print(f"Type error: {e}")
238
```