Hello all! I've been playing with string templating quite a bit lately and wrote some logic to help me with this. I found it a bit more flexible than using partial and wanted to get feedback to see if it would be worth formalizing this code into the functools module. It's pretty short so I don't think it deserves its own module, and it behaves similarly to partial but has a bit more flexibility.
Thanks for your time! ```python from functools import wraps from typing import Any, Callable, Union def lazy(func: Callable[..., Any]) -> Callable[..., Any]: """ A decorator that buffers args and kwargs gathering and function execution suspending processing until the function is called without any args or kwargs. This allows any function to support partials for decomposition out of the box. Also, supports variable length arguments and kw_arguments. Example: import math @lazy def velocity(height_m: float, acceleration_m2: float) -> float: return math.sqrt(2 * acceleration_m2 * height_m) g = -9.81 # acceleration due to gravity in m/s^2 earth = velocity(acceleration=g) v = earth(height=1)() print("The velocity is:", v, "m/s") v = earth(height=10)() print("The velocity is:", v, "m/s") v = earth(height=100)() print("The falling velocity is:", v, "m/s") """ @wraps(func) def collect(*args: Any, **kwargs: Any) -> Any: if not args and not kwargs: return func(*args, **kwargs) return ( lambda *next_args, **next_kwargs: func( *(args + next_args), **{**kwargs, **next_kwargs} ) if not next_args and not next_kwargs else collect(*(args + next_args), **{**kwargs, **next_kwargs}) ) return collect @lazy def f_string_head(f_str: str, **kwargs) -> Union[Callable[[], str], str]: """ Turns an f-string into a curry-able function, will return head to end or first KeyError when finally evaluated with no arguments. """ try: results = f_str.format_map({} if kwargs is None else kwargs) return results except KeyError as e: sub_template = f_str.split("{" + e.args[0] + "}", 1)[0] results = sub_template.format_map({} if kwargs is None else kwargs) return results def test_f_string() -> None: """ Tests the f_string function. """ template = """{one}{two}{three}""" f_one = f_string_head(template, one="1") f_one_three = f_one(three="3") f_one_two_three = f_one_three(two="2") assert f_one() == "1" assert f_one_three() == "1" assert f_one_two_three() == "123" def test_curring() -> None: @lazy def my_function(*args, **kwargs): print( "Function evaluated with arguments:", args, "and keyword arguments:", kwargs ) assert args == (1, 2, 3, 4) assert kwargs == {"a": 2, "b": 5} return "Function passed" partial_function = my_function(1, 2, a=3) result = partial_function(3, 4, b=5, a=2) results = result() print(results) def test_add() -> None: @lazy def add(*args: int, **kwargs: int) -> int: """ A function that takes any number of integer arguments and returns their sum. Args: *args: Integer arguments to be summed. **kwargs: Integer keyword arguments to be summed. Returns: The sum of the integer arguments. """ return sum(args) + sum(kwargs.values()) result = add(1)(2, 3)(4)(5, six=6)() print(f"Add={result}") def test_velocity() -> None: import math @lazy def velocity(height_m: float, acceleration_m2: float) -> float: return math.sqrt(2 * acceleration_m2 * height_m) g = 9.81 # acceleration due to gravity in m/s^2 earth = velocity(acceleration_m2=g) v = earth(height_m=5)() print("The falling velocity is:", v, "m/s") v = earth(height_m=15)() print("The falling velocity is:", v, "m/s") v = earth(height_m=30)() print("The falling velocity is:", v, "m/s") def main() -> None: """ The main function that runs the program. """ test_curring() test_add() test_f_string() test_velocity() if __name__ == "__main__": main() ``` _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SV2ZIVZVSTJYNKTTTQ6ECOWTBCWBVR77/ Code of Conduct: http://python.org/psf/codeofconduct/