Skip to content

Commit ef5e504

Browse files
Qian WenjieQian Wenjie
authored andcommitted
updated README
1 parent 8fca213 commit ef5e504

File tree

3 files changed

+122
-6
lines changed

3 files changed

+122
-6
lines changed

README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,101 @@
11
lazy-python
22
===========
3+
4+
A Python Lazy Programming library.
5+
6+
Overview
7+
-----------
8+
9+
*Lazy Evaluation* is among useful features in Functional Programming.
10+
This tool help make lazy evaluation in Python easy to use. The expression
11+
is saved in directed graph and evaluate when necessary. The evaluation
12+
leverage multicore (``multiprocessing`` library in Python) and graph cut
13+
algorithm to compute the results in parallel.
14+
15+
Examples
16+
-----------
17+
18+
This example illustrate how to calculate *Fibnoacci* by Lazy Evalution and
19+
the cache mechanism of pure function call with the same parameters.
20+
21+
>>> from lazy import Lazy
22+
>>> def fib(n):
23+
... return Lazy(int, debug=True)(n) if n <= 1 else fib(n-1) + fib(n-2)
24+
...
25+
>>> a = fib(10)
26+
>>> a
27+
(((((((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1))+(((1+int(0))+1)+(1+int(0))))+((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1)))+(((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1))+(((1+int(0))+1)+(1+int(0)))))+((((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1))+(((1+int(0))+1)+(1+int(0))))+((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1))))+(((((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1))+(((1+int(0))+1)+(1+int(0))))+((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1)))+(((((1+int(0))+1)+(1+int(0)))+((1+int(0))+1))+(((1+int(0))+1)+(1+int(0))))))
28+
>>> a.eval()
29+
int(0) == 0
30+
(1+0) == 1
31+
(1+1) == 2
32+
(2+1) == 3
33+
(3+2) == 5
34+
(5+3) == 8
35+
(8+5) == 13
36+
(13+8) == 21
37+
(21+13) == 34
38+
(34+21) == 55
39+
55
40+
>>> a
41+
55
42+
>>> b = fib(11)
43+
>>> b
44+
(55+34)
45+
>>> b.eval()
46+
(55+34) == 89
47+
89
48+
49+
Lazy Evaluation uses implicit parallel by *multiprocessing*. The following
50+
example shows how the implicit parallel works by using decorator *lazy*.
51+
52+
from lazy import lazy
53+
import time
54+
55+
def f(name):
56+
print('Enter', name)
57+
time.sleep(5)
58+
print('Leave', name)
59+
60+
@lazy
61+
def f1():
62+
f('f1')
63+
return 1
64+
65+
@lazy
66+
def f2():
67+
f('f2')
68+
return 2
69+
70+
@lazy
71+
def f3():
72+
f('f3')
73+
return 3
74+
75+
@lazy
76+
def f4():
77+
f('f4')
78+
return 4
79+
80+
if __name__ == '__main__':
81+
s = f1()*f2()+f3()*f4()
82+
print(s)
83+
s.eval()
84+
print(s)
85+
86+
$ time python3 1.py
87+
((f1()*f2())+(f3()*f4()))
88+
Enter f1
89+
Enter f2
90+
Enter f3
91+
Enter f4
92+
Leave f1
93+
Leave f3
94+
Leave f4
95+
Leave f2
96+
14
97+
98+
real 0m5.173s
99+
user 0m0.111s
100+
sys 0m0.049s
101+

lazy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from lazy import Lazy, INT
1+
from .lazy import lazy, Lazy, INT
22

lazy/lazy.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
from operator import add, sub, mul, truediv, getitem
44
import time, weakref
55

6+
def lazy(func):
7+
new_name = '_lazy_'+func.__name__
8+
globals()[new_name] = func
9+
func.__name__ = new_name
10+
func.__module__ = __name__
11+
lazyfunc = Lazy(func)
12+
return lazyfunc
13+
614
class Lazy(object):
715

816
POOL = None
@@ -14,14 +22,15 @@ class Lazy(object):
1422
@classmethod
1523
def set_cores(cls, num):
1624
cls.CORES = num
17-
def __init__(self, operator, remote=True, format='{0}({1})'):
25+
def __init__(self, operator, remote=True, format='{0}({1})', debug=False):
1826
self.operator = operator
1927
self.remote = remote
2028
self.format = format
2129
self.func = True
2230
self.depth = -1
2331
self.args = None
2432
self.waitlock = None
33+
self.debug = debug
2534
def call(self, *args):
2635
cache_key = (self.operator, args)
2736
if cache_key in Lazy.CACHES:
@@ -41,6 +50,8 @@ def call(self, *args):
4150
if i.value is None:
4251
self.argscount += 1
4352
i.waitings.append(self)
53+
if i.debug:
54+
self.debug = True
4455
if self.argscount == 0:
4556
if self.remote:
4657
Lazy.JOBS.add(self)
@@ -56,7 +67,7 @@ def setdepth(self, l=0):
5667
i.setdepth(l+(1 if i.remote else 0))
5768
self.depth = max(self.depth, l)
5869
def __call__(self, *args):
59-
s = Lazy(self.operator, self.remote, self.format)
70+
s = Lazy(self.operator, self.remote, self.format, self.debug)
6071
return s.call(*args)
6172
def __add__(self, a):
6273
return ADD(self, a)
@@ -84,11 +95,16 @@ def __eq__(self, other):
8495
return self.operator == other.operator and self.args == other.args
8596
def __hash__(self):
8697
return hash((self.operator, self.args))
98+
def opname(self):
99+
if self.operator.__name__.startswith('_lazy_'):
100+
return self.operator.__name__[6:]
101+
else:
102+
return self.operator.__name__
87103
def __str__(self):
88104
if self.func:
89-
return 'Lazy(%s)' % (self.operator.__name__,)
105+
return 'Lazy(%s)' % (self.opname(),)
90106
elif self.value is None:
91-
return self.format.format(self.operator.__name__, ', '.join(map(str, self.args)), *self.args)
107+
return self.format.format(self.opname(), ', '.join(map(str, self.args)), *self.args)
92108
else:
93109
return str(self.value)
94110
def __repr__(self):
@@ -99,7 +115,8 @@ def argsfinish(self):
99115
Lazy.JOBS.add(self)
100116
def finish(self, value):
101117
self.runtime = time.time() - self.startrun
102-
#print(self, '==', value)
118+
if self.debug:
119+
print(self, '==', value)
103120
self.value = value
104121
for i in self.waitings[:]:
105122
i.argsfinish()

0 commit comments

Comments
 (0)