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

目录
  • 背景
  • 拿来即用
  • 实践过程
  • 通过装饰器类简化代码
  • 总结

背景

每次加载数据都要重新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

总结

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

(0)

相关推荐

  • 详解Python小数据池和代码块缓存机制

    前言 本文除"总结"外,其余均为认识过程:3.7.5:这部分官方文档不知道在哪里找,目前没有找到,有谁知道的可以麻烦留言吗? 谢谢了! 总结: 如果在同一代码块下,则采用同一代码块下的缓存机制: 如果是不同代码块,则采用小数据池的驻留机制: 需要注意的是,交互式输入时,每个命令都是一个代码块: 实现 Intern 保留机制的方式非常简单,就是通过维护一个字符串储蓄池,这个池子是一个字典结构,编译时,如果字符串已经存在于池子中就不再去创建新的字符串,直接返回之前创建好的字符串对象, 如果

  • Python 分布式缓存之Reids数据类型操作详解

    1.Redis API 1.安装redis模块 $ pip3.8 install redis 2.使用redis模块 import redis # 连接redis的ip地址/主机名,port,password=None r = redis.Redis(host="127.0.0.1",port=6379,password="gs123456") 3.redis连接池 redis-py使用connection pool来管理对一个redis server的所有连接,避

  • Python的Flask框架使用Redis做数据缓存的配置方法

    Redis是一款依据BSD开源协议发行的高性能Key-Value存储系统.会把数据读入内存中提高存取效率.Redis性能极高能支持超过100K+每秒的读写频率,还支持通知key过期等等特性,所以及其适合做缓存. 下载安装 根据redis中文网使用wget下载压缩包 $ wget http://download.redis.io/releases/redis-3.0.5.tar.gz $ tar xzf redis-3.0.5.tar.gz $ cd redis-3.0.5 $ make 二进制文

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

    目录 背景 拿来即用 实践过程 通过装饰器类简化代码 总结 背景 每次加载数据都要重新Load,想通过加入的注解方式开发缓存机制,每次缓存不用写代码了 缺点:目前仅支持一个返回值,虽然能弄成字典,但是已经满足个人需求,没动力改(狗头). 拿来即用 新建文件 Cache.py class Cache: def __init__(self, cache_path='.', nocache=False): self.cache_path = cache_path self.cache = not no

  • Python解析多帧dicom数据详解

    概述 pydicom是一个常用python DICOM parser.但是,没有提供解析多帧图的示例.本文结合相关函数和DICOM知识做一个简单说明. DICOM多帧数据存储 DICOM标准中关于多帧数据存储的最重要一部分说明是PS3.5 Annex A.4 A.4 Transfer Syntaxes For Encapsulation of Encoded Pixel Data. 无论何时,Pixel Data都存放在Pixel Data (7FE0,0010)中.有可能是直接存放的(nati

  • Mybatis注解方式操作Oracle数据库详解

    1.新增多行数据 @Insert({"<script>insert all " + "<foreach collection=\"list\" index=\"index\" item=\"item\" open=\"\" separator=\"\" close=\"\">" + " into s_user (u

  • Java SpringCache+Redis缓存数据详解

    目录 前言 一.什么是SpringCache 二.项目集成Spring Cache + Redis 1.配置方式 三.使用Spring Cache 四.SpringCache原理与不足 1.读模式 2.写模式:(缓存与数据库一致) 五.总结 前言 这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!! 这里就对自己学过来的内容进行一次的总结和归纳!!! 一.什么是SpringCache Spring Cache 是一个非常优秀的缓存组件.自

  • Spring Boot 基于注解的 Redis 缓存使用详解

    看文本之前,请先确定你看过上一篇文章<Spring Boot Redis 集成配置>并保证 Redis 集成后正常可用,因为本文是基于上文继续增加的代码. 一.创建 Caching 配置类 RedisKeys.Java package com.shanhy.example.redis; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; import org.springf

  • 对Python中创建进程的两种方式以及进程池详解

    在Python中创建进程有两种方式,第一种是: from multiprocessing import Process import time def test(): while True: print('---test---') time.sleep(1) if __name__ == '__main__': p=Process(target=test) p.start() while True: print('---main---') time.sleep(1) 上面这段代码是在window

  • Python爬虫实战案例之爬取喜马拉雅音频数据详解

    前言 喜马拉雅是专业的音频分享平台,汇集了有声小说,有声读物,有声书,FM电台,儿童睡前故事,相声小品,鬼故事等数亿条音频,我最喜欢听民间故事和德云社相声集,你呢? 今天带大家爬取喜马拉雅音频数据,一起期待吧!! 这个案例的视频地址在这里 https://v.douyu.com/show/a2JEMJj3e3mMNxml 项目目标 爬取喜马拉雅音频数据 受害者地址 https://www.ximalaya.com/ 本文知识点: 1.系统分析网页性质 2.多层数据解析 3.海量音频数据保存 环境

  • Python获取网页数据详解流程

    Requests 库是 Python 中发起 HTTP 请求的库,使用非常方便简单. 发送 GET 请求 当我们用浏览器打开东旭蓝天股票首页时,发送的最原始的请求就是 GET 请求,并传入url参数. import requests url='http://push2his.eastmoney.com/api/qt/stock/fflow/daykline/get' 用Python requests库的get函数得到数据并设置requests的请求头. header={ 'User-Agent'

  • 利用Python多处理库处理3D数据详解

    今天我们将介绍处理大量数据时非常方便的工具.我不会只告诉您可能在手册中找到的一般信息,而是分享一些我发现的小技巧,例如tqdm与 multiprocessing​imap​​一起使用.并行处理档案.绘制和处理 3D 数据以及如何搜索如果您有点云,则用于对象网格中的类似对象.​ 那么我们为什么要求助于并行计算呢?如今,如果您处理任何类型的数据,您可能会面临与"大数据"相关的问题.每次我们有不适合 RAM 的数据时,我们都需要一块一块地处理它.幸运的是,现代编程语言允许我们生成在多核处理器

  • Spring Boot 使用 SSE 方式向前端推送数据详解

    目录 前言 服务端 SSE工具类 在Controller层创建 SSEController.java 前端代码 前言 SSE简单的来说就是服务器主动向前端推送数据的一种技术,它是单向的,也就是说前端是不能向服务器发送数据的.SSE适用于消息推送,监控等只需要服务器推送数据的场景中,下面是使用Spring Boot 来实现一个简单的模拟向前端推动进度数据,前端页面接受后展示进度条. 服务端 在Spring Boot中使用时需要注意,最好使用Spring Web 提供的SseEmitter这个类来进

随机推荐