Skip to content

Instantly share code, notes, and snippets.

@yassu
Created September 3, 2014 07:37
Show Gist options
  • Save yassu/ecd6153fdf2d5c63e92c to your computer and use it in GitHub Desktop.
Save yassu/ecd6153fdf2d5c63e92c to your computer and use it in GitHub Desktop.
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
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)
@tk0miya
Copy link

tk0miya commented Sep 4, 2014

ちなみに、作ってもらった 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