Turn any callable into a lazy evaluated callable. result classes or types is required -- at least one is needed so that the automatic forcing of the lazy evaluation code is triggered. Results are not memoized; the function is evaluated on every access.
(func, *resultclasses)
| 75 | |
| 76 | |
| 77 | def lazy(func, *resultclasses): |
| 78 | """ |
| 79 | Turn any callable into a lazy evaluated callable. result classes or types |
| 80 | is required -- at least one is needed so that the automatic forcing of |
| 81 | the lazy evaluation code is triggered. Results are not memoized; the |
| 82 | function is evaluated on every access. |
| 83 | """ |
| 84 | |
| 85 | class __proxy__(Promise): |
| 86 | """ |
| 87 | Encapsulate a function call and act as a proxy for methods that are |
| 88 | called on the result of that function. The function is not evaluated |
| 89 | until one of the methods on the result is called. |
| 90 | """ |
| 91 | |
| 92 | def __init__(self, args, kw): |
| 93 | self._args = args |
| 94 | self._kw = kw |
| 95 | |
| 96 | def __reduce__(self): |
| 97 | return ( |
| 98 | _lazy_proxy_unpickle, |
| 99 | (func, self._args, self._kw, *resultclasses), |
| 100 | ) |
| 101 | |
| 102 | def __deepcopy__(self, memo): |
| 103 | # Instances of this class are effectively immutable. It's just a |
| 104 | # collection of functions. So we don't need to do anything |
| 105 | # complicated for copying. |
| 106 | memo[id(self)] = self |
| 107 | return self |
| 108 | |
| 109 | def __cast(self): |
| 110 | return func(*self._args, **self._kw) |
| 111 | |
| 112 | # Explicitly wrap methods which are defined on object and hence would |
| 113 | # not have been overloaded by the loop over resultclasses below. |
| 114 | |
| 115 | def __repr__(self): |
| 116 | return repr(self.__cast()) |
| 117 | |
| 118 | def __str__(self): |
| 119 | return str(self.__cast()) |
| 120 | |
| 121 | def __eq__(self, other): |
| 122 | if isinstance(other, Promise): |
| 123 | other = other.__cast() |
| 124 | return self.__cast() == other |
| 125 | |
| 126 | def __ne__(self, other): |
| 127 | if isinstance(other, Promise): |
| 128 | other = other.__cast() |
| 129 | return self.__cast() != other |
| 130 | |
| 131 | def __lt__(self, other): |
| 132 | if isinstance(other, Promise): |
| 133 | other = other.__cast() |
| 134 | return self.__cast() < other |
no outgoing calls