*** empty log message ***
[pli.git] / pli / functional.py
blobaf57e1370c03dd31e7e274feff6e958da32b129a
1 #=======================================================================
3 __version__ = '''0.5.14'''
4 __sub_version__ = '''20041101000543'''
5 __copyright__ = '''(c) Alex A. Naanou 2003'''
8 #-----------------------------------------------------------------------
10 from __future__ import generators
11 import new
14 #-----------------------------------------------------------------------
15 #---------------------------------------------------------------apply---
16 apply = lambda func, *pargs, **nargs: func(*pargs, **nargs)
19 #--------------------------------------------------------------lcurry---
20 lcurry = lambda func, *pargs, **nargs:\
21 lambda *p, **n:\
22 func(*pargs + p, **dict(nargs.items() + n.items()))
25 #---------------------------------------------------------------curry---
26 curry = lcurry
29 #--------------------------------------------------------------rcurry---
30 # NOTE: this adds the curried args to the tail...
31 rcurry = lambda func, *pargs, **nargs:\
32 lambda *p, **n:\
33 func(*p + pargs, **dict(nargs.items() + n.items()))
36 #-----------------------------------------------------------fastcurry---
37 # Originally written by Alex Martelli
38 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/229472
39 # NOTE: though this is faster, it is also less flexible than the above
40 # variants.
41 # NOTE: here 'arg' can not be None.
42 fastcurry = lambda func, arg:\
43 new.instancemethod(func, arg, object)
46 #--------------------------------------------------------------LCurry---
47 class LCurry(object):
48 '''
49 this is the left curry class.
50 '''
51 def __new__(cls, func, *args, **kw):
52 obj = object.__new__(cls)
53 if isinstance(func, LCurry) or isinstance(func, RCurry):
54 obj._curry_func = func._curry_func
55 obj._curry_args = (func._curry_args[0] + args, func._curry_args[1])
56 obj._curry_kw = kw = kw.copy()
57 kw.update(func._curry_kw)
58 else:
59 obj._curry_func = func
60 obj._curry_args = (args, ())
61 obj._curry_kw = kw.copy()
62 return obj
63 def __call__(self, *args, **kw):
64 self._curry_func(*self._curry_args[0] + args + self._curry_args[1], **dict(self._curry_kw.items() + kw.items()))
67 #---------------------------------------------------------------Curry---
68 Curry = LCurry
71 #--------------------------------------------------------------RCurry---
72 class RCurry(object):
73 '''
74 this is the right curry class.
75 '''
76 def __new__(cls, func, *args, **kw):
77 obj = object.__new__(cls)
78 if isinstance(func, LCurry) or isinstance(func, RCurry):
79 obj._curry_func = func._curry_func
80 obj._curry_args = (func._curry_args[0] ,func._curry_args[1] + args)
81 obj._curry_kw = kw = kw.copy()
82 kw.update(func._curry_kw)
83 else:
84 obj._curry_func = func
85 obj._curry_args = ((), args)
86 obj._curry_kw = kw.copy()
87 return obj
88 def __call__(self, *args, **kw):
89 self._curry_func(*self._curry_args[0] + args + self._curry_args[1], **dict(self._curry_kw.items() + kw.items()))
92 #--------------------------------------------------------------negate---
93 # this will return a function that will return the oposite result
94 # (boolean) to the original....
95 negate = lambda f:\
96 lambda *p, **n: not f(*p, **n)
99 #------------------------------------------------------raise_on_false---
100 def raise_on_false(func, exception=Exception, name=None, msg=''):
102 this will return a function wraping func so as to raise exception(msg) if it returns false.
104 # sanity checks... ##!! TEST !!##
105 if func == None:
106 raise TypeError, 'func must not be None.'
107 if hasattr(func, '_raise_on_false_wrapped') and func._raise_on_false_wrapped:
108 raise TypeError, '%s is already wrapped, won\'t wrap agen.' % func
110 # define the function code...
111 func_txt = """def %(function_name)s(*p, **n):
112 '''wrapper of %(function_object)s callable.'''
113 res = func(*p, **n)
114 if not res:
115 raise exception, msg
116 return res"""
117 # genreate a good name if one is not given...
118 if name == None:
119 name = hasattr(func, '__name__') and func.__name__ != '<lambda>' and func.__name__ or 'Unnamed'
120 exec (func_txt % {'function_name':name, 'function_object':func}) in locals(), globals()
121 f = eval(name)
122 # marck the predicate returned... (to avoid repeated wrapping (see
123 # above))...
124 f._raise_on_false_wrapped = True
125 return f
128 ###------------------------------------------------------------iterator---
129 ##class _iterator(object):
130 ## '''
131 ## '''
132 ## def __init__(self, iter_next, iter_init, *p, **n):
133 ## '''
134 ## '''
135 ## init(self, *p, **n)
136 ## self.next = new.instancemethod(iter_next, self, iterator)
137 ## def __iter__(self):
138 ## return self
142 #-----------------------------------------------------------------------
143 ##!! THE FOLLOWING ARE EXPERIMENTAL !!##
144 #-----------------------------------------------------------------seq---
145 def seq(f0, *f):
147 seq(f0[, f1[, ...]]) -> res
148 seq(name, f0[, f1[, ...]]) -> res
150 this will return a function that when called will sequence the functions given,
151 passing its arguments into each one, and returning the list of their results.
153 NOTE: in the second form the name is used as name for the resulting function.
154 NOTE: atleast one function must be given.
156 if type(f0) is str:
157 if len(f) < 1:
158 raise TypeError, 'need atleast one callable in the sequence (got: 0).'
160 func_txt = """def %(function_name)s(*p, **n):
161 '''sequence wrapper of %(functions)s.'''
162 res = []
163 for func in f:
164 res += [func(*p, **n)]
165 return res"""
166 exec (func_txt % {'function_name':f0, 'functions':f}) in locals(), globals()
167 _seq = eval(f0)
168 else:
169 def _seq(*p, **n):
172 res = []
173 for func in (f0,) + f:
174 res += [func(*p, **n)]
175 return res
176 return _seq
180 #-----------------------------------------------------------------------
181 #--------------------------------------------------------getclasstree---
182 def getclasstree(cls, predicate=None):
183 l = []
184 for c in cls.__subclasses__():
185 if predicate != None and predicate(c):
186 l += [(c, getclasstree(c, predicate))]
187 elif predicate == None:
188 l += [(c, getclasstree(c))]
189 return l
192 #---------------------------------------------------classtreeiterdown---
193 # this is my first recursive iterator... :)
194 def classtreeiterdown(cls, predicate=None):
196 this will iterate the inheritance tree branch down.
198 for c in cls.__subclasses__():
199 if predicate != None and predicate(c):
200 yield c
201 for cls in classtreeiterdown(c, predicate):
202 yield cls
203 elif predicate == None:
204 yield c
205 for cls in classtreeiterdown(c):
206 yield cls
209 #-----------------------------------------------------classtreeiterup---
210 def classtreeiterup(cls, predicate=None):
212 this will iterate the inheritance tree up.
214 NOTE: this will not remove duplicate classes.
216 for c in cls.__bases__:
217 if predicate != None and predicate(c):
218 yield c
219 for cls in classtreeiterup(c, predicate):
220 yield cls
221 elif predicate == None:
222 yield c
223 for cls in classtreeiterup(c):
224 yield cls
228 #=======================================================================
229 # vim:set ts=4 sw=4 nowrap :