这种方法下要缓存的函数只能写作类函数,因为需要继承cacheable类。不知是否有什么改进方法?
from datetime import datetime
def cached(time):
def make_cacheable(func):
func.should_be_cached = True
func.time_out = time
return func
return make_cacheable
class Cacheable(object):
__CACHE__ = {}
def cache_that(self, func):
def wrapper(*args, **kw):
name = "%s%r%r" % (func.__name__, args, kw)
if name not in self.__CACHE__ or ( datetime.today() - self.__CACHE__["time"] ).total_seconds() > func.time_out:
self.__CACHE__[name] = func(*args, **kw)
self.__CACHE__["time"] = datetime.today()
return self.__CACHE__[name]
wrapper.__name__ = func.__name__
return wrapper
#内置函数。类中的函数每次被调用时,都是先通过该函数找到函数名对应的函数,再执行
def __getattribute__(self, attr):
function = super(Cacheable, self).__getattribute__(attr)
if attr != 'cache_that' and callable(function) and hasattr(function, 'should_be_cached'):
return self.cache_that(function)
return function
class monitor(Cacheable):
def __init__(self):
pass
@cached(100)
def fetch_list(self):
list = []
#connect db and get list
return list
顺便说说装饰器。
网上很多都说如果函数b装饰a,那么调用a就等于调用b(a)。但这种是在装饰器没有参数的前提下。当装饰器有参数时,被装饰的函数就不是相当于传递参数那样传递的了。
具体的机理我也不太懂,反正如果装饰器有参数的话,是需要在装饰器的内部再定义一个函数,然后返回这个函数。这个函数的唯一参数就是被装饰的函数名。如果该函数又需要有参数,那么就有需要在其内部定义一个函数,直到函数没有参数。注意,不是调用这个函数而是返回这个函数,因为调用的话是需要在函数名后加 () 的。而正如我上面的代码中,make_cacheable后面不带括号。
而如果被装饰的函数是带有参数的话,那么就像上面代码的cache_that一样,内部定义一个函数来接收被装饰函数的参数。
wrapper.__name__ = func.__name__的作用和@functools.warp(func)一样,是为了让函数返回时的名字不变,还是被装饰的函数的名字
如果装饰器是类,那么调用被装饰函数时就会先生成一个装饰类。
但是如果装饰器是类内函数呢?也会先生成一个装饰类,然后调用这个函数?