9
9
:target: https://travis-ci.org/kutoga/lazy-load
10
10
:alt: Latest Travis CI build status
11
11
12
- A minimalistic interface that allows lazy evaluation of expressions / function calls / ...
13
-
14
- TODO:
15
-
16
- - Add examples
17
- - Create README
18
- - Comment code
19
- - pypi
20
- - Add more tests: E.g. for properties, force_eval for callables
21
- - Tox config
12
+ A minimalistic interface that allows lazy evaluation of expressions and function calls.
22
13
23
14
Note: This small library is highly based on `python-lazy-object-proxy `.
24
15
25
16
Why using ℒazy-ℒoad? Lazy loading in general may make some software implementations much more efficient.
26
17
Especially if it is not known if some data has to be loaded or not. Often the resulting code is less efficient,
27
- because eager loading is used or the code is not elegant.
18
+ because eager loading is used or the code is not elegant, because one has to program (somehow) lazy loading .
28
19
29
20
Advantages of this library are that lazy-loading may be used quite elegant and effective.
30
21
31
22
Examples
32
23
^^^^^^^^
33
24
34
25
In a loop it might happen that a special condition appears once or even more often. If this is the case,
35
- an expensive function `expensive_function ` ha sto be called and on the resulting object an operation has
36
- to be done. The expensive function only has to be called once and the resulting object then might be
37
- reused.
26
+ an expensive function `expensive_function ` is called and on the resulting object an operation has
27
+ to be done. If the expensive function had to called more than once, than the result object may be reused.
38
28
39
29
Possible implementation:
40
30
31
+
41
32
.. code :: python
42
33
43
34
def expensive_function ():
@@ -54,6 +45,7 @@ Possible implementation:
54
45
55
46
Given this library, it might be done like this:
56
47
48
+
57
49
.. code :: python
58
50
59
51
from lazy_load import lazy
@@ -68,9 +60,55 @@ Given this library, it might be done like this:
68
60
if test_for_something(x, y, p):
69
61
obj.do_something(x, y)
70
62
71
- The expensive function is used more often and always a lazy evaluation is done. Therefore, a decorator might
72
- be used to indicate that all function calls to this function shall be lazily evaluated. This makes it possible
73
- to normally use the function. The behaviour is still the same like in the first example:
63
+ There are similar situations outside of loops. The implementation without `lazy-load ` might look like this:
64
+
65
+
66
+ .. code :: python
67
+
68
+ def expensive_function ():
69
+ print (" function evaluation" )
70
+ ...
71
+ return result
72
+
73
+ obj = None
74
+ def get_obj ():
75
+ global obj
76
+ if obj is None :
77
+ obj = expensive_function()
78
+ return obj
79
+
80
+ if condition_a:
81
+ get_obj().xyz()
82
+ if condition_b:
83
+ do_something()
84
+ if condition_c:
85
+ get_obj().abc()
86
+
87
+ This code can be realized much easier with `lazy-load `. Not only is the code shorter, but it is also more readable:
88
+
89
+
90
+ .. code :: python
91
+
92
+ from lazy_load import lazy
93
+
94
+ def expensive_function ():
95
+ print (" function evaluation" )
96
+ ...
97
+ return result
98
+
99
+ obj = lazy(expensive_function)
100
+
101
+ if condition_a:
102
+ obj.xyz()
103
+ if condition_b:
104
+ do_something()
105
+ if condition_c:
106
+ obj.abc()
107
+
108
+ It might be the case that the expensive function is used more often and always a lazy evaluation is done.
109
+ In this case, a decorator might be used to indicate that all function calls to this function shall be lazily
110
+ evaluated. This makes it possible to normally use the function. The behaviour is still the same like in the first example:
111
+
74
112
75
113
.. code :: python
76
114
@@ -87,11 +125,14 @@ to normally use the function. The behaviour is still the same like in the first
87
125
if test_for_something(x, y, p):
88
126
obj.do_something(x, y)
89
127
90
- A lazy evaluation of function / methods calls might be done with the `@lazy_func ` decorator of with the `lazy `-call. This was already
128
+ A lazy evaluation of functions / methods calls might be done with the `@lazy_func ` decorator of with the `lazy `-call. This was already
91
129
shown, therefore the following examples show how to do a one-shot lazy evaluation of a function call:
92
130
131
+
93
132
.. code :: python
94
133
134
+ from lazy_load import lazy, lz
135
+
95
136
def expensive_func (x , y ):
96
137
print (f " function evaluation with arguments x= { x} , y= { y} " )
97
138
...
@@ -100,7 +141,7 @@ shown, therefore the following examples show how to do a one-shot lazy evaluatio
100
141
# Possibility 1: Use `lazy` with a callable
101
142
obj = lazy(lambda : expensive_func(a, b))
102
143
103
- # Possibility 2: If it doesn't matter if the arguments for the expensive-function are eager evaluated, the call may be simplified:
144
+ # Possibility 2: If it doesn't matter if the argument expressions for the expensive-function are eager evaluated, the call may be simplified:
104
145
obj = lazy(expensive_func, a, b)
105
146
106
147
# Possibility 3: `lazy` has a short version / alias: `lz`
@@ -116,15 +157,16 @@ a function has the exact same signature as the original function.
116
157
One might now like to have the possibility to on-the-fly convert a callable to a lazily evaluated callable.
117
158
This might be done in the following way:
118
159
160
+
119
161
.. code :: python
120
162
163
+ from lazy_load import lazy_func, lf
164
+
121
165
def expensive_func (x ):
122
- print (d " function evaluation with argument x={x} " )
166
+ print (f " function evaluation with argument x= { x} " )
123
167
...
124
168
return result
125
169
126
- from lazy_load import lazy_func, lf
127
-
128
170
# Possibility 1: Use `lazy_func`.
129
171
my_obj.do_something(f = lazy_func(expensive_func))
130
172
@@ -137,8 +179,11 @@ This might be done in the following way:
137
179
Actually, I want to go deeper into the `ℒ`azy- or `ℒ `-"operator". This operator converts on-the-fly a function
138
180
to a lazily evaluated function. Another example:
139
181
182
+
140
183
.. code :: python
141
184
185
+ from lazy_load import ℒ
186
+
142
187
def test (name ):
143
188
print (f " hey { name} " )
144
189
return True
@@ -156,8 +201,11 @@ to a lazily evaluated function. Another example:
156
201
157
202
It is also possible to convert multiple functions to lazily evaluated functions using `ℒ `:
158
203
204
+
159
205
.. code :: python
160
206
207
+ from lazy_load import ℒ
208
+
161
209
def f1 (x ):
162
210
print (f " f1 { x} " )
163
211
return True
@@ -177,8 +225,11 @@ value are lazily evaluated. Public methods are all methods that have a name not
177
225
Methods with a return value are identificated by the given return type hint which must not be `None `.
178
226
This behaviour might be done with the `@lazy_class `-decorator (alias: `lc `):
179
227
228
+
180
229
.. code :: python
181
230
231
+ from lazy_load import lazy_class
232
+
182
233
@lazy_class
183
234
class MyClass :
184
235
def __init__ (self ):
@@ -198,20 +249,60 @@ This behaviour might be done with the `@lazy_class`-decorator (alias: `lc`):
198
249
...
199
250
return result
200
251
252
+ Finally, it is also possible to force the evaluation of a lazy loading object by using `force_eval ` (alias `fe `).
253
+ This function can safely to used to non-lazy loading objects: It is then just equal to the identity function.
254
+
255
+
256
+ .. code :: python
257
+
258
+ from lazy_load import lazy, force_eval
259
+
260
+ def f1 (x ):
261
+ print (f " f1 { x} " )
262
+ return True
263
+
264
+ lazy_obj = lazy(f1, 1 )
265
+
266
+ # The following expression prints "f1 1" and returns "True"
267
+ force_eval(lazy_obj)
268
+
269
+ The `force_eval ` function may also be applied to lazy-functions (which are created with `lazy_func(x) `, `@lazy_func `
270
+ or with `ℒ `). This restores the original non-lazy / eager function. For non-lazy functions this call has no effect:
271
+
272
+
273
+ .. code :: python
274
+
275
+ from lazy_load import lazy_func, force_eval
276
+
277
+ @lazy_func
278
+ def f (x ):
279
+ print (" hey" )
280
+ return x** 2
281
+
282
+ # The following line prints nothing
283
+ obj = f(2 )
284
+
285
+ f_eager = force_eval(f)
286
+
287
+ # The following line prints "hey" and "obj" has immediatly the value "4"
288
+ obj = f_eager(2 )
289
+
290
+
201
291
Installation
202
292
------------
203
293
204
-
294
+ ` pip install lazy-load `
205
295
206
296
Requirements
207
297
^^^^^^^^^^^^
208
298
209
- Compatibility
210
- -------------
299
+ Python 3.6 or Python 3.7.
211
300
212
301
Licence
213
302
-------
214
303
304
+ MIT
305
+
215
306
Authors
216
307
-------
217
308
0 commit comments