Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python decorate function preserving part of signature

I have written the following decorator:

def partializable(fn):
    def arg_partializer(*fixable_parameters):
        def partialized_fn(dynamic_arg):
            return fn(dynamic_arg, *fixable_parameters)

        return partialized_fn
    return arg_partializer

The purpose of this decorator is to break the function call into two calls. If I decorate the following:

@partializable
def my_fn(dyn, fix1, fix2):
    return dyn + fix1 + fix2

I then can do:

core_accepting_dynamic_argument = my_fn(my_fix_1, my_fix_2)
final_result = core_accepting_dynamic_argument(my_dyn)

My problem is that the now decorated my_fn exhibits the following signature: my_fn(*fixable_parameters)

I want it to be: my_fn(fix1, fix2)

How can I accomplish this? I probably have to use wraps or the decorator module, but I need to preserve only part of the original signature and I don't know if that's possible.

like image 547
Lester Jack Avatar asked Dec 02 '25 09:12

Lester Jack


1 Answers

Taking inspiration from https://stackoverflow.com/a/33112180/9204395, it's possible to accomplish this by manually altering the signature of arg_partializer, since only the signature of fn is known in the relevant scope and can be handled with inspect.

from inspect import signature

def partializable(fn):
    def arg_partializer(*fixable_parameters):
        def partialized_fn(dynamic_arg):
            return fn(dynamic_arg, *fixable_parameters)

        return partialized_fn

    # Override signature
    sig = signature(fn)
    sig = sig.replace(parameters=tuple(sig.parameters.values())[1:])
    arg_partializer.__signature__ = sig

    return arg_partializer

This is not particularly elegant, but as I think about the problem I'm starting to suspect that this (or a conceptual equivalent) is the only possible way to pull this stunt. Feel free to contradict me.

like image 69
Lester Jack Avatar answered Dec 04 '25 01:12

Lester Jack



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!