"""
Miscellaneous utilities
"""
import functools
class LazyProperty (object) :
"""
Lazy-loaded cached properties.
This functions by overriding the class's property attribute with the actual value attribute in the instance's
dict, causing all future attribute lookups to return that directly.
>>> class Foo (object) :
... counter = 0
... @lazy_load
... def foo (self) :
... self.counter += 1
... return self.counter
...
>>> foo = Foo(); foo.foo, foo.foo, foo.counter
(1, 1, 1)
"""
def __init__ (self, func) :
"""
Initialize with no value
"""
# the getter function
self.func = func
# the attribute name
self.name = func.__name__
def run (self, obj) :
"""
Run the background func and return the to-be-cached value.
`obj` is the object instance
"""
return self.func(obj)
def store (self, obj, value) :
"""
Store the cached value, overring ourself
"""
# print "[%x] %r.__dict__[%r] = %r" % (id(obj), obj, self.name, value)
obj.__dict__[self.name] = value
def __get__ (self, obj, owner) :
"""
Generate the value, store it as the attribute and return it.
"""
# compute value
value = self.run(obj)
# store it
self.store(obj, value)
# return it
return value
class LazyIteratorProperty (LazyProperty) :
"""
A lazy-loaded property that automatically converts an iterator/genexp into a non-mutable tuple.
"""
def run (self, obj) :
return tuple(self.func(obj))
lazy_load = LazyProperty
lazy_load_iter = LazyIteratorProperty
def first (iterable) :
"""
Returns the first item from the iterable that evaluates to True, otherwise None.
>>> first((0, 1))
1
>>> first("abc")
'a'
>>> first(('', list(), (), False))
None
"""
for item in iterable :
if item :
return item
else :
return None
# testing
if __name__ == '__main__' :
import doctest
doctest.testmod()