I'm creating a wrapper for a function with functools.wraps. My wrapper has the effect of overriding a default parameter (and it doesn't do anything else):
def add(*, a=1, b=2):
"Add numbers"
return a + b
@functools.wraps(add)
def my_add(**kwargs):
kwargs.setdefault('b', 3)
return add(**kwargs)
This my_add definition behaves the same as
@functools.wraps(add)
def my_add(*, a=1, b=3):
return add(a=a, b=b)
except that I didn't have to manually type out the parameter list.
However, when I run help(my_add), I see the help string for add, which has the wrong function name and the wrong default argument for the parameter b:
add(*, a=1, b=2)
Add numbers
How can I override the function name and the default argument in this help() output?
(Or, is there a different way to define my_add, using for example some magic function my_add = magic(add, func_name='my_add', kwarg_defaults={'b': 3}) that will do what I want?)
Let me try and explain what happens.
When you call the
helpfunctions, this is going to request information about your function using the inspect module. Therefore you have to change the function signature, in order to change the default argument.Now this is not something that is advised, or often preferred, but who cares about that right? The provided solution is considered hacky and probably won't work for all versions of Python. Therefore you might want to reconsider how important the
helpfunction is... Any way let's start with some explanation on how it was done, followed by the code and test case.Copying functions
Now the first thing we will do is copy the entire function, this is because I only want to change the signature of the new function and not the original function. This decouples the new
my_addsignature (and default values) from the originaladdfunction.See:
For ideas of how to do this (I will show my version in a bit).
Copying / updating signature
The next step is to get a copy of the function signature, for that this post was very useful. Except for the part where we have to adjust the signature parameters to match the new keyword default arguments.
For that we have to change the value of a
mappingproxy, which we can see when running the debugger on the return value ofinspect.signature(g). Now so far this can only be done by changing the private variables (the values with leading underscores_private). Therefore this solution will be considered hacky and is not guaranteed to withstand possible updates. That said, let's see the solution!Full code
Example
Output
Usages
f: is the function that you want to updatefunc_name: is optionally the new name of the function (if empty, keeps the old name)update_kwargs: is a dictionary containing the key and value of the default arguments that you want to update.Notes
copyvariables to make full copies of dictionaries, such that there is no impact on the originaladdfunction._defaultvalue is a private variable, and can be changed in future releases of python.