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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/SV2ZIVZVSTJYNKTTTQ6ECOWTBCWBVR77/
Code of Conduct: http://python.org/psf/codeofconduct/