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/

Reply via email to