146 classes or types -- at least one is needed so that the automatic forcing of |
146 classes or types -- at least one is needed so that the automatic forcing of |
147 the lazy evaluation code is triggered. Results are not memoized; the |
147 the lazy evaluation code is triggered. Results are not memoized; the |
148 function is evaluated on every access. |
148 function is evaluated on every access. |
149 """ |
149 """ |
150 class __proxy__(Promise): |
150 class __proxy__(Promise): |
151 # This inner class encapsulates the code that should be evaluated |
151 """ |
152 # lazily. On calling of one of the magic methods it will force |
152 Encapsulate a function call and act as a proxy for methods that are |
153 # the evaluation and store the result. Afterwards, the result |
153 called on the result of that function. The function is not evaluated |
154 # is delivered directly. So the result is memoized. |
154 until one of the methods on the result is called. |
|
155 """ |
|
156 __dispatch = None |
|
157 |
155 def __init__(self, args, kw): |
158 def __init__(self, args, kw): |
156 self.__func = func |
159 self.__func = func |
157 self.__args = args |
160 self.__args = args |
158 self.__kw = kw |
161 self.__kw = kw |
159 self.__dispatch = {} |
162 if self.__dispatch is None: |
|
163 self.__prepare_class__() |
|
164 |
|
165 def __prepare_class__(cls): |
|
166 cls.__dispatch = {} |
160 for resultclass in resultclasses: |
167 for resultclass in resultclasses: |
161 self.__dispatch[resultclass] = {} |
168 cls.__dispatch[resultclass] = {} |
162 for (k, v) in resultclass.__dict__.items(): |
169 for (k, v) in resultclass.__dict__.items(): |
163 setattr(self, k, self.__promise__(resultclass, k, v)) |
170 if hasattr(cls, k): |
164 self._delegate_str = str in resultclasses |
171 continue |
165 self._delegate_unicode = unicode in resultclasses |
172 setattr(cls, k, cls.__promise__(resultclass, k, v)) |
166 assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types." |
173 cls._delegate_str = str in resultclasses |
167 if self._delegate_unicode: |
174 cls._delegate_unicode = unicode in resultclasses |
168 # Each call to lazy() makes a new __proxy__ object, so this |
175 assert not (cls._delegate_str and cls._delegate_unicode), "Cannot call lazy() with both str and unicode return types." |
169 # doesn't interfere with any other lazy() results. |
176 if cls._delegate_unicode: |
170 __proxy__.__unicode__ = __proxy__.__unicode_cast |
177 cls.__unicode__ = cls.__unicode_cast |
171 elif self._delegate_str: |
178 elif cls._delegate_str: |
172 __proxy__.__str__ = __proxy__.__str_cast |
179 cls.__str__ = cls.__str_cast |
173 |
180 __prepare_class__ = classmethod(__prepare_class__) |
174 def __promise__(self, klass, funcname, func): |
181 |
|
182 def __promise__(cls, klass, funcname, func): |
175 # Builds a wrapper around some magic method and registers that magic |
183 # Builds a wrapper around some magic method and registers that magic |
176 # method for the given type and method name. |
184 # method for the given type and method name. |
177 def __wrapper__(*args, **kw): |
185 def __wrapper__(self, *args, **kw): |
178 # Automatically triggers the evaluation of a lazy value and |
186 # Automatically triggers the evaluation of a lazy value and |
179 # applies the given magic method of the result type. |
187 # applies the given magic method of the result type. |
180 res = self.__func(*self.__args, **self.__kw) |
188 res = self.__func(*self.__args, **self.__kw) |
181 return self.__dispatch[type(res)][funcname](res, *args, **kw) |
189 for t in type(res).mro(): |
182 |
190 if t in self.__dispatch: |
183 if klass not in self.__dispatch: |
191 return self.__dispatch[t][funcname](res, *args, **kw) |
184 self.__dispatch[klass] = {} |
192 raise TypeError("Lazy object returned unexpected type.") |
185 self.__dispatch[klass][funcname] = func |
193 |
|
194 if klass not in cls.__dispatch: |
|
195 cls.__dispatch[klass] = {} |
|
196 cls.__dispatch[klass][funcname] = func |
186 return __wrapper__ |
197 return __wrapper__ |
|
198 __promise__ = classmethod(__promise__) |
187 |
199 |
188 def __unicode_cast(self): |
200 def __unicode_cast(self): |
189 return self.__func(*self.__args, **self.__kw) |
201 return self.__func(*self.__args, **self.__kw) |
190 |
202 |
191 def __str_cast(self): |
203 def __str_cast(self): |