| Index: infra/libs/decorators/decorators.py
|
| diff --git a/infra/libs/decorators/decorators.py b/infra/libs/decorators/decorators.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f3b48f03a8aef4cd3c7195cd4c7dcf10f8604a8e
|
| --- /dev/null
|
| +++ b/infra/libs/decorators/decorators.py
|
| @@ -0,0 +1,56 @@
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import functools
|
| +
|
| +
|
| +class cached_property(object):
|
| + """Like @property, except that the result of get is cached on
|
| + self.{'_' + fn.__name__}.
|
| +
|
| + NOTE: This implementation is not threadsafe.
|
| +
|
| + >>> class Test(object):
|
| + ... @cached_property
|
| + ... def foo(self):
|
| + ... print "hello"
|
| + ... return 10
|
| + ...
|
| + >>> t = Test()
|
| + >>> t.foo
|
| + hello
|
| + 10
|
| + >>> t.foo
|
| + 10
|
| + >>> t.foo = 20
|
| + >>> t.foo
|
| + 20
|
| + >>> del t.foo
|
| + >>> t.foo
|
| + hello
|
| + 10
|
| + >>>
|
| + """
|
| + def __init__(self, fn):
|
| + self.func = fn
|
| + self._iname = "_" + fn.__name__
|
| + functools.update_wrapper(self, fn)
|
| +
|
| + def __get__(self, inst, cls=None):
|
| + if inst is None:
|
| + return self
|
| + if not hasattr(inst, self._iname):
|
| + val = self.func(inst)
|
| + # Some methods call out to another layer to calculate the value. This
|
| + # higher layer will assign directly to the property, so we have to do
|
| + # the extra hasattr here to determine if the value has been set as a side
|
| + # effect of func()
|
| + if not hasattr(inst, self._iname):
|
| + setattr(inst, self._iname, val)
|
| + return getattr(inst, self._iname)
|
| +
|
| + def __delete__(self, inst):
|
| + assert inst is not None
|
| + if hasattr(inst, self._iname):
|
| + delattr(inst, self._iname)
|
|
|