I would like to create a decorator for dynamically assigning function signatures to decorated functions, something like this:
import inspect
signature = inspect.Signature([
inspect.Parameter('x', kind=inspect.Parameter.KEYWORD_ONLY, default=None),
inspect.Parameter('y', kind=inspect.Parameter.KEYWORD_ONLY, default=None),
inspect.Parameter('z', kind=inspect.Parameter.KEYWORD_ONLY, default=None)])
def with_signature(signature:inspect.Signature):
def _decor(f):
def _wrapper():
...
return _wrapper
return _decor
@with_signature(signature):
def fun():
return [x, y, z]
fun
should now have a signature as if it had been defined literally with def fun(x=None, y=None, z=None)
. Also type hints in the signature would be great.
How to go about this?
Edit
I came up with a somewhat kludgy solution:
def with_signature(signature:inspect.Signature):
def _decor(f):
@functools.wraps(f)
def _wrapper(**kwargs):
signature.bind(**kwargs)
_f = types.FunctionType(
f.__code__,
kwargs
)
return _f()
return _wrapper
return _decor
This allows to write:
signature = inspect.Signature([
inspect.Parameter('x', kind=inspect.Parameter.KEYWORD_ONLY, default=None),
inspect.Parameter('y', kind=inspect.Parameter.KEYWORD_ONLY, default=None),
inspect.Parameter('z', kind=inspect.Parameter.KEYWORD_ONLY, default=None)])
@with_signature(signature)
def fun():
return [x, y, z]
print(fun(x=1, z=3, y=2))
The idea is to check **kwargs
with signature.bind
, then create a function and provide **kwargs
as globals
. This is obviously pretty ugly, and in fact doesn't do what I want, i.e. actually change the decorated function's signature. So I'd appreciate any help.
Edit 2:
The whole endeavour seems rather unpythonic to me now. What I actually want is to provide a definite function interface, so using **kwargs
with typing_extension.Unpack
and a typing.TypedDict
might be a good way to go.
from typing import TypedDict
from typing_extensions import Unpack
class Signature(TypedDict):
x: int = 0
y: int = 0
z: int = 0
def fun(**kwargs: Unpack[Signature]):
...
I think I'll use that for now, but still the OP problem seems interesing to me, so I'm still looking forward to suggestions and ideas.