makefun library
makefun is a small Python library for dynamically creating functions and modifying existing function signatures at runtime. It is currently at version 1.16.0 and maintains an active development cycle with regular updates, including support for new Python versions and bug fixes.
Warnings
- breaking Version 1.16.0 (and later) drops official support for Python versions older than 3.9. If you are using Python 3.8 or earlier, you must pin makefun to a version less than 1.16.0.
- gotcha The behavior of `wraps` was updated in version 1.15.0 to be more compliant with PEP 362 regarding the setting of `__wrapped__` and `__signature__` attributes. While generally an improvement, this could subtly change behavior for applications inadvertently relying on the pre-1.15.0 `wraps` implementation.
- gotcha Prior to version 1.15.3, creating functions where a default argument's value was a subclass of a basic primitive (e.g., `int` or `str`) could lead to a `SyntaxError: invalid syntax`.
- gotcha Versions prior to 1.15.2 could raise a `SyntaxError` if a native coroutine function's name contained the substring `'return'`.
- gotcha In Python 2, prior to version 1.15.1, creating functions with names starting or ending with `_`, or containing `__`, could result in a `ValueError: Invalid co_name`.
Install
-
pip install makefun
Imports
- create_function
from makefun import create_function
- create_wrapper
from makefun import create_wrapper
- wraps
from makefun import wraps
- with_signature
from makefun import with_signature
Quickstart
from makefun import create_function, wraps
from inspect import Signature, Parameter
# Example 1: Creating a function from scratch
def my_implementation(a, b):
return f"a={a}, b={b}"
sig = Signature([
Parameter('a', Parameter.POSITIONAL_OR_KEYWORD),
Parameter('b', Parameter.POSITIONAL_OR_KEYWORD, default=2)
])
dynamic_func = create_function(sig, my_implementation, doc="A dynamically created function")
print(dynamic_func(1)) # Output: a=1, b=2
print(dynamic_func(10, b=20)) # Output: a=10, b=20
# Example 2: Wrapping an existing function and changing its signature
def original(x, y):
return x * y
@wraps(original, new_sig=Signature([Parameter('val', Parameter.POSITIONAL_OR_KEYWORD)]))
def my_wrapper(val):
# original expects x, y. Let's map 'val' to both.
return original(val, val)
print(my_wrapper(val=5)) # Output: 25