| | 5 | |
|---|
| | 6 | class NoneSoFar: |
|---|
| | 7 | """ |
|---|
| | 8 | NoneSoFar is a singleton that denotes a missing value. This can be |
|---|
| | 9 | used instead of None - because None might be a valid return value. |
|---|
| | 10 | """ |
|---|
| | 11 | pass |
|---|
| | 12 | NoneSoFar = NoneSoFar() |
|---|
| | 13 | |
|---|
| | 14 | def force(value): |
|---|
| | 15 | """ |
|---|
| | 16 | This function forces evaluation of a promise. It recognizes a promise |
|---|
| | 17 | by it's magic __force__ function and just applies it and returns |
|---|
| | 18 | the result. If the value isn't a promise, it just returns the value. |
|---|
| | 19 | """ |
|---|
| | 20 | |
|---|
| | 21 | return getattr(value, '__force__', lambda : value)() |
|---|
| | 22 | |
|---|
| | 23 | def forced(value): |
|---|
| | 24 | """ |
|---|
| | 25 | This function returns true if a value is either not a promise or |
|---|
| | 26 | is already forced. This uses the __forced__ magic method. |
|---|
| | 27 | """ |
|---|
| | 28 | return getattr(value, '__forced__', lambda : True)() |
|---|
| | 29 | |
|---|
| | 30 | def lazy(func, *resultclasses): |
|---|
| | 31 | |
|---|
| | 32 | """ |
|---|
| | 33 | lazy turns any callable passed in into a lazy evaluated callable. |
|---|
| | 34 | you need to give result classes or types - at least one is needed |
|---|
| | 35 | so that the automatic forcing of the lazy evaluation code is |
|---|
| | 36 | triggered. |
|---|
| | 37 | """ |
|---|
| | 38 | |
|---|
| | 39 | class __proxy__: |
|---|
| | 40 | |
|---|
| | 41 | """ |
|---|
| | 42 | This inner class encapsulates the code that should be evaluated |
|---|
| | 43 | lazyly. On calling of one of the magic methods it will force |
|---|
| | 44 | the evaluation and store the result - afterwards the result |
|---|
| | 45 | is delivered directly. So the result is memoized. |
|---|
| | 46 | """ |
|---|
| | 47 | |
|---|
| | 48 | def __init__(self, args, kw): |
|---|
| | 49 | self.__func = func |
|---|
| | 50 | self.__args = args |
|---|
| | 51 | self.__kw = kw |
|---|
| | 52 | self.__result = NoneSoFar |
|---|
| | 53 | self.__dispatch = {} |
|---|
| | 54 | for resultclass in resultclasses: |
|---|
| | 55 | self.__dispatch[resultclass] = {} |
|---|
| | 56 | for (k, v) in resultclass.__dict__.items(): |
|---|
| | 57 | setattr(self, k, self.__promise__(resultclass, k, v)) |
|---|
| | 58 | |
|---|
| | 59 | def __force__(self): |
|---|
| | 60 | """ |
|---|
| | 61 | This function forces the evaluation of a promise and |
|---|
| | 62 | returns the value itself. |
|---|
| | 63 | """ |
|---|
| | 64 | if self.__result is NoneSoFar: |
|---|
| | 65 | self.__result = self.__func(*self.__args, **self.__kw) |
|---|
| | 66 | return self.__result |
|---|
| | 67 | |
|---|
| | 68 | def __forced__(self): |
|---|
| | 69 | """ |
|---|
| | 70 | This returns true if the promise is forced and false if not. |
|---|
| | 71 | """ |
|---|
| | 72 | if self.__result is NoneSoFar: return False |
|---|
| | 73 | else: return True |
|---|
| | 74 | |
|---|
| | 75 | def __promise__(self, klass, funcname, func): |
|---|
| | 76 | |
|---|
| | 77 | """ |
|---|
| | 78 | This function builds a wrapper around some magic method and |
|---|
| | 79 | registers that magic method for the given type and methodname. |
|---|
| | 80 | """ |
|---|
| | 81 | |
|---|
| | 82 | def __wrapper__(*args, **kw): |
|---|
| | 83 | """ |
|---|
| | 84 | This wrapper function automatically forces the evaluation of |
|---|
| | 85 | a lazy value if the value isn't already forced. It then applies |
|---|
| | 86 | the given magic method of the result type. |
|---|
| | 87 | """ |
|---|
| | 88 | res = self.__force__() |
|---|
| | 89 | return self.__dispatch[type(res)][funcname](res, *args, **kw) |
|---|
| | 90 | |
|---|
| | 91 | if not self.__dispatch.has_key(klass): self.__dispatch[klass] = {} |
|---|
| | 92 | self.__dispatch[klass][funcname] = func |
|---|
| | 93 | return __wrapper__ |
|---|
| | 94 | |
|---|
| | 95 | def __wrapper__(*args, **kw): |
|---|
| | 96 | """ |
|---|
| | 97 | This wrapper function just creates the proxy object that is returned |
|---|
| | 98 | instead of the actual value. |
|---|
| | 99 | """ |
|---|
| | 100 | return __proxy__(args, kw) |
|---|
| | 101 | |
|---|
| | 102 | return __wrapper__ |
|---|
| | 103 | |
|---|
| | 104 | if __name__ == '__main__': |
|---|
| | 105 | def anton(a,b): |
|---|
| | 106 | return a+b |
|---|
| | 107 | |
|---|
| | 108 | anton = lazy(anton, int, str) |
|---|
| | 109 | |
|---|
| | 110 | print type(anton(5,6)) |
|---|
| | 111 | print anton(5,6) |
|---|
| | 112 | print anton('anton','berta') |
|---|
| | 113 | print type(force(anton(5,6))) |
|---|
| | 114 | print forced(1) |
|---|
| | 115 | print forced(anton(5,6)) |
|---|
| | 116 | print forced(force(anton(5,6))) |
|---|
| | 117 | |
|---|