vse_sim.decorators
1import time 2from functools import update_wrapper, wraps 3from inspect import getfullargspec, isfunction 4from itertools import starmap 5 6_missing = object() 7 8 9def decorator(d): 10 "Make function d a decorator: d wraps a function fn." 11 12 def _d(fn): 13 return update_wrapper(d(fn), fn) 14 15 return _d 16 17 18decorator = decorator(decorator)(decorator) 19 20 21def setdefaultattr(obj, name, value): 22 try: 23 return getattr(obj, name) 24 except AttributeError: 25 setattr(obj, name, value) 26 return value 27 28 29def autoassign(*names, **kwargs): 30 """ 31 autoassign(function) -> method 32 autoassign(*argnames) -> decorator 33 autoassign(exclude=argnames) -> decorator 34 35 allow a method to assign (some of) its arguments as attributes of 36 'self' automatically. E.g. 37 38 >>> class Foo(object): 39 ... @autoassign 40 ... def __init__(self, foo, bar): pass 41 ... 42 >>> breakfast = Foo('spam', 'eggs') 43 >>> breakfast.foo, breakfast.bar 44 ('spam', 'eggs') 45 46 To restrict autoassignment to 'bar' and 'baz', write: 47 48 @autoassign('bar', 'baz') 49 def method(self, foo, bar, baz): ... 50 51 To prevent 'foo' and 'baz' from being autoassigned, use: 52 53 @autoassign(exclude=('foo', 'baz')) 54 def method(self, foo, bar, baz): ... 55 """ 56 if kwargs: 57 exclude, f = set(kwargs["exclude"]), None 58 sieve = lambda l: filter(lambda nv: nv[0] not in exclude, l) 59 elif len(names) == 1 and isfunction(names[0]): 60 f = names[0] 61 sieve = lambda l: l 62 else: 63 names, f = set(names), None 64 sieve = lambda l: [nv for nv in l if nv[0] in names] 65 66 def decorator(f): 67 spec = getfullargspec(f) 68 fargnames, fdefaults = spec.args, spec.defaults 69 # Remove self from fargnames and make sure fdefault is a tuple 70 fargnames, fdefaults = fargnames[1:], fdefaults or () 71 defaults = list(sieve(zip(reversed(fargnames), reversed(fdefaults)))) 72 73 @wraps(f) 74 def decorated(self, *args, **kwargs): 75 assigned = dict(sieve(zip(fargnames, args))) 76 assigned.update(sieve(kwargs.items())) 77 for _ in starmap(assigned.setdefault, defaults): 78 pass 79 self.__dict__.update(assigned) 80 return f(self, *args, **kwargs) 81 82 return decorated 83 84 return f and decorator(f) or decorator 85 86 87import functools 88 89 90@decorator 91class memoized(object): 92 """Decorator. Caches a function's return value each time it is called. 93 If called later with the same arguments, the cached value is returned 94 (not reevaluated). 95 """ 96 97 def __init__(self, func): 98 self.func = func 99 self.cache = {} 100 101 def __call__(self, *args): 102 try: 103 return self.cache[args] 104 except KeyError: 105 pass 106 except TypeError: 107 return self.func(*args) 108 value = self.func(*args) 109 self.cache[args] = value 110 return value 111 112 def __repr__(self): 113 """Return the function's docstring.""" 114 return self.func.__doc__ 115 116 def __get__(self, obj, objtype): 117 """Support instance methods.""" 118 return functools.partial(self.__call__, obj) 119 120 121@decorator 122class cached_property(object): 123 """A decorator that converts a function into a lazy property. The 124 function wrapped is called the first time to retrieve the result 125 and then that calculated result is used the next time you access 126 the value:: 127 128 class Foo(object): 129 130 @cached_property 131 def foo(self): 132 # calculate something important here 133 return 42 134 135 The class has to have a `__dict__` in order for this property to 136 work. 137 """ 138 139 # implementation detail: this property is implemented as non-data 140 # descriptor. non-data descriptors are only invoked if there is 141 # no entry with the same name in the instance's __dict__. 142 # this allows us to completely get rid of the access function call 143 # overhead. If one choses to invoke __get__ by hand the property 144 # will still work as expected because the lookup logic is replicated 145 # in __get__ for manual invocation. 146 147 def __init__(self, func, name=None, doc=None): 148 self.__name__ = name or func.__name__ 149 self.__module__ = func.__module__ 150 self.__doc__ = doc or func.__doc__ 151 self.func = func 152 153 def __get__(self, obj, type=None): 154 if obj is None: 155 return self 156 value = obj.__dict__.get(self.__name__, _missing) 157 if value is _missing: 158 value = self.func(obj) 159 obj.__dict__[self.__name__] = value 160 return value 161 162 163class curried(object): 164 """ 165 Decorator that returns a function that keeps returning functions 166 until all arguments are supplied; then the original function is 167 evaluated. 168 """ 169 170 def __init__(self, func, *a): 171 self.func = func 172 self.args = a 173 174 def __call__(self, *a): 175 args = self.args + a 176 if len(args) < self.func.__code__.co_argcount: 177 return curried(self.func, *args) 178 else: 179 return self.func(*args) 180 181 182@decorator 183def timeit(method): 184 185 def timed(*args, **kw): 186 ts = time.time() 187 result = method(*args, **kw) 188 te = time.time() 189 190 print("%r (%r, %r) %2.2f sec" % (method.__name__, args, kw, te - ts)) 191 return result 192 193 return timed 194 195 196__all__ = [ 197 "autoassign", 198 "cached_property", 199 "curried", 200 "decorator", 201 "memoized", 202 "setdefaultattr", 203 "timeit", 204]
30def autoassign(*names, **kwargs): 31 """ 32 autoassign(function) -> method 33 autoassign(*argnames) -> decorator 34 autoassign(exclude=argnames) -> decorator 35 36 allow a method to assign (some of) its arguments as attributes of 37 'self' automatically. E.g. 38 39 >>> class Foo(object): 40 ... @autoassign 41 ... def __init__(self, foo, bar): pass 42 ... 43 >>> breakfast = Foo('spam', 'eggs') 44 >>> breakfast.foo, breakfast.bar 45 ('spam', 'eggs') 46 47 To restrict autoassignment to 'bar' and 'baz', write: 48 49 @autoassign('bar', 'baz') 50 def method(self, foo, bar, baz): ... 51 52 To prevent 'foo' and 'baz' from being autoassigned, use: 53 54 @autoassign(exclude=('foo', 'baz')) 55 def method(self, foo, bar, baz): ... 56 """ 57 if kwargs: 58 exclude, f = set(kwargs["exclude"]), None 59 sieve = lambda l: filter(lambda nv: nv[0] not in exclude, l) 60 elif len(names) == 1 and isfunction(names[0]): 61 f = names[0] 62 sieve = lambda l: l 63 else: 64 names, f = set(names), None 65 sieve = lambda l: [nv for nv in l if nv[0] in names] 66 67 def decorator(f): 68 spec = getfullargspec(f) 69 fargnames, fdefaults = spec.args, spec.defaults 70 # Remove self from fargnames and make sure fdefault is a tuple 71 fargnames, fdefaults = fargnames[1:], fdefaults or () 72 defaults = list(sieve(zip(reversed(fargnames), reversed(fdefaults)))) 73 74 @wraps(f) 75 def decorated(self, *args, **kwargs): 76 assigned = dict(sieve(zip(fargnames, args))) 77 assigned.update(sieve(kwargs.items())) 78 for _ in starmap(assigned.setdefault, defaults): 79 pass 80 self.__dict__.update(assigned) 81 return f(self, *args, **kwargs) 82 83 return decorated 84 85 return f and decorator(f) or decorator
autoassign(function) -> method autoassign(*argnames) -> decorator autoassign(exclude=argnames) -> decorator
allow a method to assign (some of) its arguments as attributes of 'self' automatically. E.g.
>>> class Foo(object):
... @autoassign
... def __init__(self, foo, bar): pass
...
>>> breakfast = Foo('spam', 'eggs')
>>> breakfast.foo, breakfast.bar
('spam', 'eggs')
To restrict autoassignment to 'bar' and 'baz', write:
@autoassign('bar', 'baz')
def method(self, foo, bar, baz): ...
To prevent 'foo' and 'baz' from being autoassigned, use:
@autoassign(exclude=('foo', 'baz'))
def method(self, foo, bar, baz): ...
122@decorator 123class cached_property(object): 124 """A decorator that converts a function into a lazy property. The 125 function wrapped is called the first time to retrieve the result 126 and then that calculated result is used the next time you access 127 the value:: 128 129 class Foo(object): 130 131 @cached_property 132 def foo(self): 133 # calculate something important here 134 return 42 135 136 The class has to have a `__dict__` in order for this property to 137 work. 138 """ 139 140 # implementation detail: this property is implemented as non-data 141 # descriptor. non-data descriptors are only invoked if there is 142 # no entry with the same name in the instance's __dict__. 143 # this allows us to completely get rid of the access function call 144 # overhead. If one choses to invoke __get__ by hand the property 145 # will still work as expected because the lookup logic is replicated 146 # in __get__ for manual invocation. 147 148 def __init__(self, func, name=None, doc=None): 149 self.__name__ = name or func.__name__ 150 self.__module__ = func.__module__ 151 self.__doc__ = doc or func.__doc__ 152 self.func = func 153 154 def __get__(self, obj, type=None): 155 if obj is None: 156 return self 157 value = obj.__dict__.get(self.__name__, _missing) 158 if value is _missing: 159 value = self.func(obj) 160 obj.__dict__[self.__name__] = value 161 return value
A decorator that converts a function into a lazy property. The function wrapped is called the first time to retrieve the result and then that calculated result is used the next time you access the value::
class Foo(object):
@cached_property
def foo(self):
# calculate something important here
return 42
The class has to have a __dict__ in order for this property to
work.
164class curried(object): 165 """ 166 Decorator that returns a function that keeps returning functions 167 until all arguments are supplied; then the original function is 168 evaluated. 169 """ 170 171 def __init__(self, func, *a): 172 self.func = func 173 self.args = a 174 175 def __call__(self, *a): 176 args = self.args + a 177 if len(args) < self.func.__code__.co_argcount: 178 return curried(self.func, *args) 179 else: 180 return self.func(*args)
Decorator that returns a function that keeps returning functions until all arguments are supplied; then the original function is evaluated.
10def decorator(d): 11 "Make function d a decorator: d wraps a function fn." 12 13 def _d(fn): 14 return update_wrapper(d(fn), fn) 15 16 return _d
Make function d a decorator: d wraps a function fn.
91@decorator 92class memoized(object): 93 """Decorator. Caches a function's return value each time it is called. 94 If called later with the same arguments, the cached value is returned 95 (not reevaluated). 96 """ 97 98 def __init__(self, func): 99 self.func = func 100 self.cache = {} 101 102 def __call__(self, *args): 103 try: 104 return self.cache[args] 105 except KeyError: 106 pass 107 except TypeError: 108 return self.func(*args) 109 value = self.func(*args) 110 self.cache[args] = value 111 return value 112 113 def __repr__(self): 114 """Return the function's docstring.""" 115 return self.func.__doc__ 116 117 def __get__(self, obj, objtype): 118 """Support instance methods.""" 119 return functools.partial(self.__call__, obj)
Decorator. Caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned (not reevaluated).