Created
September 3, 2014 07:37
-
-
Save yassu/ecd6153fdf2d5c63e92c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from random import randint | |
from inspect import isfunction | |
def get_random(): | |
return randint(0, 10**10) | |
class Cacher: | |
pass | |
DEFAULT_CACHER = Cacher() | |
def memoize(func, cacher=DEFAULT_CACHER): | |
""" | |
cacher: instance that has no __slot__ | |
""" | |
def _cache(*args, **kw): | |
cached_varname = '__cache{}'.format(id(func.__call__)) | |
cached_varname += '__' | |
## several-times computation | |
if hasattr(cacher, cached_varname) is True: | |
return getattr(cacher, cached_varname) | |
## first computation | |
result = func(*args, **kw) | |
setattr(cacher, cached_varname, result) | |
return result | |
return _cache | |
def cached_property(func, cacher=DEFAULT_CACHER): | |
@property | |
@memoize | |
def _cache_property(*args, **kw): | |
return func(*args, **kw) | |
return _cache_property | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from sys import path | |
path.append('src') | |
from cache import memoize, cached_property | |
def only_func_test(): | |
global x | |
x = 1 | |
@memoize | |
def multiple(): | |
global x | |
x *= 2 | |
return x | |
for i in range(10): | |
res = multiple() | |
print('res: ' + str(res)) | |
assert(res == 2) | |
def class_simple_attr_test(): | |
class TwoTimes(): | |
def __init__(self): | |
self._value = 1 | |
@memoize | |
def multiple(self): | |
self._value *= 2 | |
return self._value | |
cls = TwoTimes() | |
for _ in range(10): | |
assert(cls.multiple() == 2) | |
def cached_property_simple_class_test(): | |
class TwoTimes(): | |
def __init__(self): | |
self._value = 1 | |
@cached_property | |
def multiple(self): | |
self._value *= 2 | |
return self._value | |
cls = TwoTimes() | |
for _ in range(10): | |
assert(cls.multiple == 2) | |
def cached_property_same_cacher_and_method_test(): | |
class TwoTimes(): | |
def __init__(self, value): | |
self._value = value | |
@cached_property | |
def multiple(self): | |
self._value *= 2 | |
return self._value | |
t1 = TwoTimes(1) | |
assert(t1.multiple == 2) | |
# multiple of default casher is equal to 2 | |
t2 = TwoTimes(5) | |
assert(t2.multiple == 10) | |
def cached_property_different_class_and_same_method_test(): | |
class TwoTimes(): | |
def __init__(self, value): | |
self._value = value | |
@cached_property | |
def multiple(self): | |
self._value *= 2 | |
return self._value | |
class ThreeTimes(): | |
def __init__(self, value): | |
self._value = value | |
@cached_property | |
def multiple(self): | |
self._value *= 3 | |
return self._value | |
t1 = TwoTimes(1) | |
assert(t1.multiple == 2) | |
# multiple of default casher is equal to 2 | |
t2 = ThreeTimes(5) | |
assert(t2.multiple == 15) | |
def cached_property_same_class_and_method_test(): | |
class TwoTimes(): | |
def __init__(self, value): | |
self._value = value | |
@cached_property | |
def multiple(self): | |
self._value *= 2 | |
return self._value | |
t1 = TwoTimes(1) | |
assert(t1.multiple == 2) | |
del(t1) | |
t2 = TwoTimes(5) | |
assert(t2.multiple == 10) |
ちなみに、作ってもらった memoize()
と cached_property()
には cacher
という引数が定義されていますが、
普通のデコレータの呼び方 (@memoize
) の場合はここを指定することが難しそうです。
引数を取るデコレータを作る場合は
def decorator(*dargs, **dkwargs):
def internal_decorator(func):
def wrapper(*args, **kwargs):
# some process
return wrapper
return internal_decorator
のように「デコレータを返す関数」を用意することになります(やたらとややこしいですね)。
参考まで。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
デバッグしてみましたが、やはり
_cache_property()
が@memoize
されているようなので、@memoize
を使うことを諦めて作りなおしてみました。https://gist.github.com/1bd5b7623f77115923ff
memoize() の変更点
id(func)
の方がよかったかも...)functools.wraps()
を使って、関数の属性(doc や name など) を維持するようにしたcached_property() の変更点
self
の属性に変更 (インスタンスが消滅すると一緒に GC されるので省メモリ)functools.wraps()
を使って、関数の属性(doc や name など) を維持するようにした