Python Forum
partial functions before knowing the values - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: partial functions before knowing the values (/thread-41325.html)



partial functions before knowing the values - mikisDeWitte - Dec-22-2023

Hello python experts!

I'm working on a function ("salary_or_name_builder" in the example) that routes my input parameters to multiple functions.
Ideally, (for decoupling purposes) that function lets another function decide the scenario and use that scenario to simply execute the function.
The issue is that my two functions salary_func & age_func take a different number of arguments.
I know I can modify salary_func so that it gets a third parameter that it doesn't use, but that sounds sloppy.
Does anyone have a tip to handle this "gracefully"?

from typing import Union


def salary_func(base_salary: int, yearly_bonus: int) -> None:
    print(f"you're expected to make {12*base_salary + yearly_bonus} / year")


def age_func(year:int, month:int, day:int) -> None:
    print(f"you were born on {day}-{month}-{year}")


def determine_scenario(param: Union[int, None]) -> str:
    if param is None:
        return salary_func
    else:
        return age_func


def salary_or_name_builder(param1: int, param2: int, param3: Union[int, None] = None) -> None:
    call = determine_scenario(param3)
    call(param1, param2, param3)


salary_or_name_builder(2000, 1, 1)  # works OK!
salary_or_name_builder(2800, 10000)  # salary_func() takes 2 positional arguments but 3 were given
My best effort so far was modifying my salary_or_name_builder with functools.partial like this

from functools import partial
...
def salary_or_name_builder(param1: int, param2: int, param3: Union[int, None] = None) -> None:
    call = determine_scenario(param3)
    if getattr(call, '__name__', repr(callable)) == "age_func":
        call = partial(call, day=param3)

    call(param1, param2)
But that kind of beats the purpose of the abstraction (since it needs to know all the possible inputs).
Is this the most graceful solution?
I was also thinking of using *args & **kwargs, but I find that syntax bad for readibility. I know what my functions need and I don't want to "mask" that Smile

Thanks for any suggestion!
Mikis


partial functions before knowing the values - mikisDeWitte - Dec-22-2023

Woops - Duplicate post


RE: partial functions before knowing the values - buran - Dec-22-2023

(Dec-22-2023, 03:25 PM)mikisDeWitte Wrote: I was also thinking of using *args & **kwargs, but I find that syntax bad for readibility.
using *args and **kwargs is perfectly fine. Actually for me it's hard to see any benefit from this dispatch function salary_or_name_builder you try to create for some "abstraction".


RE: partial functions before knowing the values - mikisDeWitte - Dec-22-2023

(Dec-22-2023, 05:46 PM)buran Wrote:
(Dec-22-2023, 03:25 PM)mikisDeWitte Wrote: I was also thinking of using *args & **kwargs, but I find that syntax bad for readibility.
using *args and **kwargs is perfectly fine. Actually for me it's hard to see any benefit from this dispatch function salary_or_name_builder you try to create for some "abstraction".

perhaps it's taste, but with args & kwargs the first 10 lines of each function would be to get the arguments from the args & kwargs.
I find it less readible because if I compare these two, I much prefer the first one
def func1(a: int, b:int, c:str) -> None:
    ...


def func2(*args, **kwargs) -> None:
    a: int = kwargs.get("a")
    b: int = kwargs.get("b")
    c: int = kwargs.get("c")
    ...
I do need to decide somewhere somehow which route my data needs to take. Is this dispatching function too far fetched?
My reason for building it is mostly to have a central place for logging the chosen scenario and also to extend the options in a flexible way.
Perhaps I'm just overthinking it after watching a lot of arjancodes design patterns on youtube Huh


RE: partial functions before knowing the values - perfringo - Dec-24-2023

According to PEP 484 shouldn’t this be the intended way:

def spam(*args: int):
    # do_something