diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-lazy-load.spec | 565 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 567 insertions, 0 deletions
@@ -0,0 +1 @@ +/lazy_load-0.8.3.tar.gz diff --git a/python-lazy-load.spec b/python-lazy-load.spec new file mode 100644 index 0000000..97ee4ec --- /dev/null +++ b/python-lazy-load.spec @@ -0,0 +1,565 @@ +%global _empty_manifest_terminate_build 0 +Name: python-lazy-load +Version: 0.8.3 +Release: 1 +Summary: ℒazy-ℒoad - A minimalistic interface that allows the lazy evaluation of expressions. Additional functions and wrappers allow it to easily use the lazy evaluation for functions and classes. +License: MIT +URL: https://github.com/kutoga/lazy-load +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/80/0c/36859ba71fb3e47505afeb61b21fef848c5afb54e119537a685b4e1adc0e/lazy_load-0.8.3.tar.gz +BuildArch: noarch + +Requires: python3-lazy-object-proxy + +%description +A minimalistic interface that allows lazy evaluation of expressions and function calls. +Note: This small library is heavily based on `python-lazy-object-proxy`. +Why using ℒazy-ℒoad? Lazy loading in general may make some software implementations much more efficient. +Especially if it is not known if some data has to be loaded or not. Often the resulting code is less efficient, +because eager loading is used or the code is not elegant, because one has to program (somehow) lazy loading. +Advantages of this library are that lazy-loading may be used quite elegant and effective. +Examples +^^^^^^^^ +In a loop it might happen that a special condition appears once or even more often. If this is the case, +an expensive function `expensive_function` is called and on the resulting object an operation has +to be done. If the expensive function had to called more than once, than the result object may be reused. +Possible implementation: + def expensive_function(): + print("function evaluation") + return result + obj = None + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + if obj is None: + obj = expensive_function() + obj.do_something(x, y) +Given this library, it might be done like this: + from lazy_load import lazy + def expensive_function(): + print("function evaluation") + return result + obj = lazy(expensive_function) + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + obj.do_something(x, y) +There are similar situations outside of loops. The implementation without `lazy-load` might look like this: + def expensive_function(): + print("function evaluation") + return result + obj = None + def get_obj(): + global obj + if obj is None: + obj = expensive_function() + return obj + if condition_a: + get_obj().xyz() + if condition_b: + do_something() + if condition_c: + get_obj().abc() +This code can be realized much easier with `lazy-load`. Not only is the code shorter, but it is also more readable: + from lazy_load import lazy + def expensive_function(): + print("function evaluation") + return result + obj = lazy(expensive_function) + if condition_a: + obj.xyz() + if condition_b: + do_something() + if condition_c: + obj.abc() +It might be the case that the expensive function is used more often and always a lazy evaluation is done. +In this case, a decorator might be used to indicate that all function calls to this function shall be lazily +evaluated. This makes it possible to normally use the function. The behaviour is still the same like in the first example: + from lazy_load import lazy_func + @lazy_func + def expensive_function(): + print("function evaluation") + return result + obj = expensive_function() + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + obj.do_something(x, y) +A lazy evaluation of functions / methods calls might be done with the `@lazy_func` decorator of with the `lazy`-call. This was already +shown, therefore the following examples show how to do a one-shot lazy evaluation of a function call: + from lazy_load import lazy, lz + def expensive_func(x, y): + print(f"function evaluation with arguments x={x}, y={y}") + return result + # Possibility 1: Use `lazy` with a callable + obj = lazy(lambda: expensive_func(a, b)) + # Possibility 2: If it doesn't matter if the argument expressions for the expensive-function are eager evaluated, the call may be simplified: + obj = lazy(expensive_func, a, b) + # Possibility 3: `lazy` has a short version / alias: `lz` + obj = lz(expensive_func, a, b) +Python allows it to pass functions around: This is often used for callbacks, but also for other use cases. +Assuming an expensive function is passed to an object which calls this function and stores the result of +the function call in an attribute. Later it might happen that this attribute is used. Depending on the +program flow it also might happen that this attribute is not used. With a lazily evaluated function the +expensive function call is only executed if the result is really used. The lazily evaluated version of +a function has the exact same signature as the original function. +One might now like to have the possibility to on-the-fly convert a callable to a lazily evaluated callable. +This might be done in the following way: + from lazy_load import lazy_func, lf + def expensive_func(x): + print(f"function evaluation with argument x={x}") + return result + # Possibility 1: Use `lazy_func`. + my_obj.do_something(f=lazy_func(expensive_func)) + # Possibility 2: Use `lf` which is an alias of `lazy_func` + my_obj.do_something(f=lf(expensive_func)) + # Possibility 3: Use the `ℒ`-"operator" + my_obj.do_something(f=ℒ[expensive_func]) +Actually, I want to go deeper into the `ℒ`azy- or `ℒ`-"operator". This operator converts on-the-fly a function +to a lazily evaluated function. Another example: + from lazy_load import ℒ + def test(name): + print(f"hey {name}") + return True + res = test("peter") + # prints "hey peter" + test_l = ℒ[test] + res = test_l("hans") + # prints nothing + if res: + print("res is True") + # prints "hey hans\nres is True" +It is also possible to convert multiple functions to lazily evaluated functions using `ℒ`: + from lazy_load import ℒ + def f1(x): + print(f"f1 {x}") + return True + def f2(x): + print(f"f1 {x}") + return True + f1_l, f2_l, f3_l = ℒ[f1, f2, lambda x: x == 1] + # This is equal to: + f1_l = ℒ[f1] + f2_l = ℒ[f2] + f3_l = ℒ[lambda x: x == 1] +Finally, one might like to decorate a class in a way that all its public methods which have a return +value are lazily evaluated. Public methods are all methods that have a name not starting with `_`. +Methods with a return value are identificated by the given return type hint which must not be `None`. +This behaviour might be done with the `@lazy_class`-decorator (alias: `lc`): + from lazy_load import lazy_class + @lazy_class + class MyClass: + def __init__(self): + # Method name starts with "_" => is not public; therefore it is eager evaluated + pass + def setX(x) -> None: + # Method does not return a value => therefore it is eager evaluated + def do(): + # Method does not hav a return value type hint => therefore it is eager evaluated + def compute() -> int: + # Method will always be lazily evaluated + return result +Finally, it is also possible to force the evaluation of a lazy loading object by using `force_eval` (alias `fe`). +This function can safely to used to non-lazy loading objects: It is then just equal to the identity function. + from lazy_load import lazy, force_eval + def f1(x): + print(f"f1 {x}") + return True + lazy_obj = lazy(f1, 1) + # The following expression prints "f1 1" and returns "True" + force_eval(lazy_obj) +The `force_eval` function may also be applied to lazy-functions (which are created with `lazy_func(x)`, `@lazy_func` +or with `ℒ`). This restores the original non-lazy / eager function. For non-lazy functions this call has no effect: + from lazy_load import lazy_func, force_eval + @lazy_func + def f(x): + print("hey") + return x**2 + # The following line prints nothing + obj = f(2) + f_eager = force_eval(f) + # The following line prints "hey" and "obj" has immediatly the value "4" + obj = f_eager(2) + +%package -n python3-lazy-load +Summary: ℒazy-ℒoad - A minimalistic interface that allows the lazy evaluation of expressions. Additional functions and wrappers allow it to easily use the lazy evaluation for functions and classes. +Provides: python-lazy-load +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-lazy-load +A minimalistic interface that allows lazy evaluation of expressions and function calls. +Note: This small library is heavily based on `python-lazy-object-proxy`. +Why using ℒazy-ℒoad? Lazy loading in general may make some software implementations much more efficient. +Especially if it is not known if some data has to be loaded or not. Often the resulting code is less efficient, +because eager loading is used or the code is not elegant, because one has to program (somehow) lazy loading. +Advantages of this library are that lazy-loading may be used quite elegant and effective. +Examples +^^^^^^^^ +In a loop it might happen that a special condition appears once or even more often. If this is the case, +an expensive function `expensive_function` is called and on the resulting object an operation has +to be done. If the expensive function had to called more than once, than the result object may be reused. +Possible implementation: + def expensive_function(): + print("function evaluation") + return result + obj = None + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + if obj is None: + obj = expensive_function() + obj.do_something(x, y) +Given this library, it might be done like this: + from lazy_load import lazy + def expensive_function(): + print("function evaluation") + return result + obj = lazy(expensive_function) + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + obj.do_something(x, y) +There are similar situations outside of loops. The implementation without `lazy-load` might look like this: + def expensive_function(): + print("function evaluation") + return result + obj = None + def get_obj(): + global obj + if obj is None: + obj = expensive_function() + return obj + if condition_a: + get_obj().xyz() + if condition_b: + do_something() + if condition_c: + get_obj().abc() +This code can be realized much easier with `lazy-load`. Not only is the code shorter, but it is also more readable: + from lazy_load import lazy + def expensive_function(): + print("function evaluation") + return result + obj = lazy(expensive_function) + if condition_a: + obj.xyz() + if condition_b: + do_something() + if condition_c: + obj.abc() +It might be the case that the expensive function is used more often and always a lazy evaluation is done. +In this case, a decorator might be used to indicate that all function calls to this function shall be lazily +evaluated. This makes it possible to normally use the function. The behaviour is still the same like in the first example: + from lazy_load import lazy_func + @lazy_func + def expensive_function(): + print("function evaluation") + return result + obj = expensive_function() + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + obj.do_something(x, y) +A lazy evaluation of functions / methods calls might be done with the `@lazy_func` decorator of with the `lazy`-call. This was already +shown, therefore the following examples show how to do a one-shot lazy evaluation of a function call: + from lazy_load import lazy, lz + def expensive_func(x, y): + print(f"function evaluation with arguments x={x}, y={y}") + return result + # Possibility 1: Use `lazy` with a callable + obj = lazy(lambda: expensive_func(a, b)) + # Possibility 2: If it doesn't matter if the argument expressions for the expensive-function are eager evaluated, the call may be simplified: + obj = lazy(expensive_func, a, b) + # Possibility 3: `lazy` has a short version / alias: `lz` + obj = lz(expensive_func, a, b) +Python allows it to pass functions around: This is often used for callbacks, but also for other use cases. +Assuming an expensive function is passed to an object which calls this function and stores the result of +the function call in an attribute. Later it might happen that this attribute is used. Depending on the +program flow it also might happen that this attribute is not used. With a lazily evaluated function the +expensive function call is only executed if the result is really used. The lazily evaluated version of +a function has the exact same signature as the original function. +One might now like to have the possibility to on-the-fly convert a callable to a lazily evaluated callable. +This might be done in the following way: + from lazy_load import lazy_func, lf + def expensive_func(x): + print(f"function evaluation with argument x={x}") + return result + # Possibility 1: Use `lazy_func`. + my_obj.do_something(f=lazy_func(expensive_func)) + # Possibility 2: Use `lf` which is an alias of `lazy_func` + my_obj.do_something(f=lf(expensive_func)) + # Possibility 3: Use the `ℒ`-"operator" + my_obj.do_something(f=ℒ[expensive_func]) +Actually, I want to go deeper into the `ℒ`azy- or `ℒ`-"operator". This operator converts on-the-fly a function +to a lazily evaluated function. Another example: + from lazy_load import ℒ + def test(name): + print(f"hey {name}") + return True + res = test("peter") + # prints "hey peter" + test_l = ℒ[test] + res = test_l("hans") + # prints nothing + if res: + print("res is True") + # prints "hey hans\nres is True" +It is also possible to convert multiple functions to lazily evaluated functions using `ℒ`: + from lazy_load import ℒ + def f1(x): + print(f"f1 {x}") + return True + def f2(x): + print(f"f1 {x}") + return True + f1_l, f2_l, f3_l = ℒ[f1, f2, lambda x: x == 1] + # This is equal to: + f1_l = ℒ[f1] + f2_l = ℒ[f2] + f3_l = ℒ[lambda x: x == 1] +Finally, one might like to decorate a class in a way that all its public methods which have a return +value are lazily evaluated. Public methods are all methods that have a name not starting with `_`. +Methods with a return value are identificated by the given return type hint which must not be `None`. +This behaviour might be done with the `@lazy_class`-decorator (alias: `lc`): + from lazy_load import lazy_class + @lazy_class + class MyClass: + def __init__(self): + # Method name starts with "_" => is not public; therefore it is eager evaluated + pass + def setX(x) -> None: + # Method does not return a value => therefore it is eager evaluated + def do(): + # Method does not hav a return value type hint => therefore it is eager evaluated + def compute() -> int: + # Method will always be lazily evaluated + return result +Finally, it is also possible to force the evaluation of a lazy loading object by using `force_eval` (alias `fe`). +This function can safely to used to non-lazy loading objects: It is then just equal to the identity function. + from lazy_load import lazy, force_eval + def f1(x): + print(f"f1 {x}") + return True + lazy_obj = lazy(f1, 1) + # The following expression prints "f1 1" and returns "True" + force_eval(lazy_obj) +The `force_eval` function may also be applied to lazy-functions (which are created with `lazy_func(x)`, `@lazy_func` +or with `ℒ`). This restores the original non-lazy / eager function. For non-lazy functions this call has no effect: + from lazy_load import lazy_func, force_eval + @lazy_func + def f(x): + print("hey") + return x**2 + # The following line prints nothing + obj = f(2) + f_eager = force_eval(f) + # The following line prints "hey" and "obj" has immediatly the value "4" + obj = f_eager(2) + +%package help +Summary: Development documents and examples for lazy-load +Provides: python3-lazy-load-doc +%description help +A minimalistic interface that allows lazy evaluation of expressions and function calls. +Note: This small library is heavily based on `python-lazy-object-proxy`. +Why using ℒazy-ℒoad? Lazy loading in general may make some software implementations much more efficient. +Especially if it is not known if some data has to be loaded or not. Often the resulting code is less efficient, +because eager loading is used or the code is not elegant, because one has to program (somehow) lazy loading. +Advantages of this library are that lazy-loading may be used quite elegant and effective. +Examples +^^^^^^^^ +In a loop it might happen that a special condition appears once or even more often. If this is the case, +an expensive function `expensive_function` is called and on the resulting object an operation has +to be done. If the expensive function had to called more than once, than the result object may be reused. +Possible implementation: + def expensive_function(): + print("function evaluation") + return result + obj = None + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + if obj is None: + obj = expensive_function() + obj.do_something(x, y) +Given this library, it might be done like this: + from lazy_load import lazy + def expensive_function(): + print("function evaluation") + return result + obj = lazy(expensive_function) + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + obj.do_something(x, y) +There are similar situations outside of loops. The implementation without `lazy-load` might look like this: + def expensive_function(): + print("function evaluation") + return result + obj = None + def get_obj(): + global obj + if obj is None: + obj = expensive_function() + return obj + if condition_a: + get_obj().xyz() + if condition_b: + do_something() + if condition_c: + get_obj().abc() +This code can be realized much easier with `lazy-load`. Not only is the code shorter, but it is also more readable: + from lazy_load import lazy + def expensive_function(): + print("function evaluation") + return result + obj = lazy(expensive_function) + if condition_a: + obj.xyz() + if condition_b: + do_something() + if condition_c: + obj.abc() +It might be the case that the expensive function is used more often and always a lazy evaluation is done. +In this case, a decorator might be used to indicate that all function calls to this function shall be lazily +evaluated. This makes it possible to normally use the function. The behaviour is still the same like in the first example: + from lazy_load import lazy_func + @lazy_func + def expensive_function(): + print("function evaluation") + return result + obj = expensive_function() + for x, y, p in get_coordinates(): + if test_for_something(x, y, p): + obj.do_something(x, y) +A lazy evaluation of functions / methods calls might be done with the `@lazy_func` decorator of with the `lazy`-call. This was already +shown, therefore the following examples show how to do a one-shot lazy evaluation of a function call: + from lazy_load import lazy, lz + def expensive_func(x, y): + print(f"function evaluation with arguments x={x}, y={y}") + return result + # Possibility 1: Use `lazy` with a callable + obj = lazy(lambda: expensive_func(a, b)) + # Possibility 2: If it doesn't matter if the argument expressions for the expensive-function are eager evaluated, the call may be simplified: + obj = lazy(expensive_func, a, b) + # Possibility 3: `lazy` has a short version / alias: `lz` + obj = lz(expensive_func, a, b) +Python allows it to pass functions around: This is often used for callbacks, but also for other use cases. +Assuming an expensive function is passed to an object which calls this function and stores the result of +the function call in an attribute. Later it might happen that this attribute is used. Depending on the +program flow it also might happen that this attribute is not used. With a lazily evaluated function the +expensive function call is only executed if the result is really used. The lazily evaluated version of +a function has the exact same signature as the original function. +One might now like to have the possibility to on-the-fly convert a callable to a lazily evaluated callable. +This might be done in the following way: + from lazy_load import lazy_func, lf + def expensive_func(x): + print(f"function evaluation with argument x={x}") + return result + # Possibility 1: Use `lazy_func`. + my_obj.do_something(f=lazy_func(expensive_func)) + # Possibility 2: Use `lf` which is an alias of `lazy_func` + my_obj.do_something(f=lf(expensive_func)) + # Possibility 3: Use the `ℒ`-"operator" + my_obj.do_something(f=ℒ[expensive_func]) +Actually, I want to go deeper into the `ℒ`azy- or `ℒ`-"operator". This operator converts on-the-fly a function +to a lazily evaluated function. Another example: + from lazy_load import ℒ + def test(name): + print(f"hey {name}") + return True + res = test("peter") + # prints "hey peter" + test_l = ℒ[test] + res = test_l("hans") + # prints nothing + if res: + print("res is True") + # prints "hey hans\nres is True" +It is also possible to convert multiple functions to lazily evaluated functions using `ℒ`: + from lazy_load import ℒ + def f1(x): + print(f"f1 {x}") + return True + def f2(x): + print(f"f1 {x}") + return True + f1_l, f2_l, f3_l = ℒ[f1, f2, lambda x: x == 1] + # This is equal to: + f1_l = ℒ[f1] + f2_l = ℒ[f2] + f3_l = ℒ[lambda x: x == 1] +Finally, one might like to decorate a class in a way that all its public methods which have a return +value are lazily evaluated. Public methods are all methods that have a name not starting with `_`. +Methods with a return value are identificated by the given return type hint which must not be `None`. +This behaviour might be done with the `@lazy_class`-decorator (alias: `lc`): + from lazy_load import lazy_class + @lazy_class + class MyClass: + def __init__(self): + # Method name starts with "_" => is not public; therefore it is eager evaluated + pass + def setX(x) -> None: + # Method does not return a value => therefore it is eager evaluated + def do(): + # Method does not hav a return value type hint => therefore it is eager evaluated + def compute() -> int: + # Method will always be lazily evaluated + return result +Finally, it is also possible to force the evaluation of a lazy loading object by using `force_eval` (alias `fe`). +This function can safely to used to non-lazy loading objects: It is then just equal to the identity function. + from lazy_load import lazy, force_eval + def f1(x): + print(f"f1 {x}") + return True + lazy_obj = lazy(f1, 1) + # The following expression prints "f1 1" and returns "True" + force_eval(lazy_obj) +The `force_eval` function may also be applied to lazy-functions (which are created with `lazy_func(x)`, `@lazy_func` +or with `ℒ`). This restores the original non-lazy / eager function. For non-lazy functions this call has no effect: + from lazy_load import lazy_func, force_eval + @lazy_func + def f(x): + print("hey") + return x**2 + # The following line prints nothing + obj = f(2) + f_eager = force_eval(f) + # The following line prints "hey" and "obj" has immediatly the value "4" + obj = f_eager(2) + +%prep +%autosetup -n lazy-load-0.8.3 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-lazy-load -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Wed May 10 2023 Python_Bot <Python_Bot@openeuler.org> - 0.8.3-1 +- Package Spec generated @@ -0,0 +1 @@ +1fcfeaba2d746dd00435477fc81d075f lazy_load-0.8.3.tar.gz |
