1 """This module defines closures.
2 Closures are functions that have been supplied with some arguments,
3 but not all of them.
4 """
5
6
7
9 """Just a marker, indicating that a certain argument is not yet
10 present, and the actual call should be deferred until later.
11 """
12
15
16
20
21
22
24 - def __init__(self, fcn, *argv, **kwarg):
25 """Create a closure by memorizing a function and its
26 arguments. If all arguments are supplied, you
27 can get the result by calling the closure without arguments.
28 Missing arguments are replaced by instances of class NotYet;
29 such arguments will need to be supplied when the closure is
30 called.
31
32 As an additional feature, you can supply a list of users
33 of the function's value. When the value is (eventually)
34 produced, the user function(s) will be called with the
35 closure's return value. Users must be functions of one
36 argument.
37 """
38 self.fcn = fcn
39 self.args = argv
40 self.argd = kwarg
41 self.deferred = []
42 self.to_be_filled = []
43 for (i, arg) in enumerate(argv):
44 if arg is NotYet:
45 self.to_be_filled.append(i)
46
48 return '%s(%s)' % (str(self.fcn),
49 ','.join([str(q) for q in self.args]
50 + ["%s=%s" % kv for kv in self.argd.items()])
51 )
52
54 """This evaluates the closure to either produce a value
55 or raise an exception.
56 """
57 lstbf = len(self.to_be_filled)
58 if len(argv) < lstbf:
59 raise ArgUnspecifiedError, len(argv)
60 a = list(self.args)
61 for (tmparg,j) in zip(argv, self.to_be_filled):
62 a[j] = tmparg
63 a.extend( argv[lstbf:] )
64 adict = self.argd.copy()
65 adict.update(argd)
66 rv = self.fcn(*a, **adict)
67 for user in self.deferred:
68 user(rv)
69 return rv
70
72 """This evaluates the closure to produce another
73 (more complete) closure. Users are not preserved.
74 """
75 a = list(self.args)
76 for (tmparg,j) in zip(argv, self.to_be_filled):
77 a[j] = tmparg
78 lstbf = len(self.to_be_filled)
79 a.extend( argv[lstbf:] )
80 adict = self.argd.copy()
81 adict.update(argd)
82 rv = Closure(self.fcn, *a, **adict)
83 return rv
84
86 """This will call the specified function when the closure
87 is completed. It's a bit of a kluge.
88 """
89 self.deferred.append( user )
90
91
92
93
94 if __name__ == '__main__':
97
98 x = Closure(foo)
99 assert x(1, 3)==4
100
101 x = Closure(foo, 3)
102 assert x(4)==7
103
104 try:
105 x(1, 1)
106 except TypeError:
107 pass
108 else:
109 print "Whoops! Expected TypeError"
110
111 try:
112 x()
113 except TypeError:
114 pass
115 else:
116 print "Whoops! Expected TypeError"
117
118 assert x(b=7)==10
119
120 try:
121 x(a=7)
122 except TypeError:
123 pass
124 else:
125 print "Whoops! Expected TypeError"
126
127
130
131 y = Closure(bar)
132 assert y(a=1)==8
133 assert y(a=1,b=2)==2
134
135 y = Closure(bar, 3, 3)
136 assert y()==9
137
138 y = Closure(bar, NotYet, 7)
139
140 try:
141 y()
142 except TypeError:
143 pass
144 else:
145 print "Whoops! Expected TypeError"
146
147 assert y(7)==49
148 z = y.partial()
149 assert z(7)==49
150 z = y.partial(8)
151 assert z()==56
153 raise RuntimeError, str(x)
154 z.defer(user1)
155 try:
156 z()
157 except RuntimeError, x:
158 assert str(x) == "56"
159 pass
160