新闻动态

Python 注解方式实现缓存数据详解

发布日期:2021-12-23 09:32 | 文章来源:源码中国

背景

每次加载数据都要重新Load,想通过加入的注解方式开发缓存机制,每次缓存不用写代码了

缺点:目前仅支持一个返回值,虽然能弄成字典,但是已经满足个人需求,没动力改(狗头)。

拿来即用

新建文件 Cache.py

class Cache:
 def __init__(self, cache_path='.', nocache=False):
  self.cache_path = cache_path
  self.cache = not nocache
 def __call__(self, func):
  @wraps(func)
  def wrapper(*args, **kwargs):
s = f'{func.__code__.co_filename}.{func.__name__}'
s += ','.join(list(args[1:]) + [f'{k}={v}' for k, v in kwargs.items()])
md5 = hashlib.md5()
md5.update(s.encode('utf-8'))
cache_file = f'{self.cache_path}/{md5.hexdigest()}'
if self.cache and os.path.exists(cache_file):
 print('Loading from cache')
 return pickle.load(open(cache_file, 'rb'))
else:
 if not os.path.exists(self.cache_path):
  os.makedirs(self.cache_path)
 data = func(*args, **kwargs)
 pickle.dump(data, file=open(cache_file, 'wb'))
 print(f'Dump finished {cache_file}')
return data
  return wrapper
from .Cache import Cache
@Cache(root_path, nocache=True)
def load_data(self, inpath):
 return 'Wula~a~a~!'

实践过程

第一次,来个简单的继承父类

class Cache(object):
 def __init__(self, cache_path=None):
  self.cache_path = cache_path if cache_path else '.'
  self.cache_path = f'{self.cache_path}/cache'
  self.data = self.load_cache()
 def load_cache(self):
  if os.path.exists(self.cache_path):
print('Loading from cache')
return pickle.load(open(self.cache_path, 'rb'))
  else:
return None
 def save_cache(self):
  pickle.dump(self.data, file=open(self.cache_path, 'wb'))
  print(f'Dump finished {self.cache_path}')
class Filter4Analyzer(Cache):
 def __init__(self, rootpath, datapath):
  super().__init__(rootpath)
  self.root_path = rootpath
  if self.data is None:
self.data = self.load_data(datapath)
self.save_cache()

只要继承Cache类就可以啦,但是有很多局限,例如只能指定某个参数被cache,例如还得在Filter4Analyzer里面写保存的代码。

下一步,python嵌套装饰器来改善这个问题

from functools import wraps
import hashlib
def cached(cache_path):
 def wrapperper(func):
  @wraps(func)
  def wrapper(*args, **kwargs):
s = f'{func.__code__.co_filename}.{func.__name__}' + ','.join(args[1:])
s += ','.join(list(args[1:]) + [f'{k}={v}' for k, v in kwargs.items()])
md5 = hashlib.md5()
md5.update(s.encode('utf-8'))
cache_file = f'{cache_path}/{md5.hexdigest()}' if cache_path else './cache'
if os.path.exists(cache_file):
 print('Loading from cache')
 return pickle.load(open(cache_file, 'rb'))
else:
 if not os.path.exists(cache_path):
  os.makedirs(cache_path)
 data = func(*args, **kwargs)
 pickle.dump(data, file=open(cache_file, 'wb'))
 print(f'Dump finished {cache_file}')
return data
  return wrapper
 return wrapperper
class Tester:
 @cached(cache_path='./workpath_test')
 def test(self, data_path):
  return ['hiahia']

通过装饰器类简化代码

class Cache:
 def __init__(self, cache_path='.', nocache=False):
  self.cache_path = cache_path
  self.cache = not nocache
 def __call__(self, func):
  @wraps(func)
  def wrapper(*args, **kwargs):
s = f'{func.__code__.co_filename}.{func.__name__}'
s += ','.join(list(args[1:]) + [f'{k}={v}' for k, v in kwargs.items()])
md5 = hashlib.md5()
md5.update(s.encode('utf-8'))
cache_file = f'{self.cache_path}/{md5.hexdigest()}'
if self.cache and os.path.exists(cache_file):
 print('Loading from cache')
 return pickle.load(open(cache_file, 'rb'))
else:
 if not os.path.exists(self.cache_path):
  os.makedirs(self.cache_path)
 data = func(*args, **kwargs)
 pickle.dump(data, file=open(cache_file, 'wb'))
 print(f'Dump finished {cache_file}')
return data
  return wrapper

参考:

Python 函数装饰器

Python函数属性和PyCodeObject

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注本站的更多内容!

版权声明:本站文章来源标注为YINGSOO的内容版权均为本站所有,欢迎引用、转载,请保持原文完整并注明来源及原文链接。禁止复制或仿造本网站,禁止在非www.yingsoo.com所属的服务器上建立镜像,否则将依法追究法律责任。本站部分内容来源于网友推荐、互联网收集整理而来,仅供学习参考,不代表本站立场,如有内容涉嫌侵权,请联系alex-e#qq.com处理。

相关文章

实时开通

自选配置、实时开通

免备案

全球线路精选!

全天候客户服务

7x24全年不间断在线

专属顾问服务

1对1客户咨询顾问

在线
客服

在线客服:7*24小时在线

客服
热线

400-630-3752
7*24小时客服服务热线

关注
微信

关注官方微信
顶部
请您留言

YINGSOO400-630-3752

提交