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

Chloe
Chloe
发布时间:2026-10-14| 6人浏览过
原创

本文介绍如何在 Python 中通过注解方式实现数据缓存机制,避免每次加载数据时重新执行 Load 操作。文章从基础的 Cache 类继承方案入手,分析其局限性,随后通过嵌套装饰器类进行优化,简化代码实现。内容涵盖缓存路径配置、MD5 哈希文件名生成、pickle 序列化存储及加载逻辑,并提供了完整的代码示例与注意事项。

背景介绍

在数据处理过程中,每次加载数据都需要重新执行 Load 操作,效率较低。为了解决这一问题,希望通过引入注解(Annotation)方式开发一套缓存机制,使得在后续使用中无需编写额外的缓存处理代码,从而简化开发流程。

需要注意的是,当前实现的方案存在一定局限性:目前仅支持单个返回值的缓存。尽管技术上可以扩展为支持字典等复杂结构,但由于当前功能已满足个人使用需求,暂无进一步修改的动力。

快速上手指南

要使用此功能,只需新建一个名为 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 类即可启用缓存,但该方法存在诸多局限。例如,只能指定特定参数进行缓存,且还需要在 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

总结

以上就是本文关于 Python 注解方式实现缓存数据的详细介绍,希望能为大家提供有益的帮助。如果您觉得内容有用,欢迎持续关注本站以获取更多技术更新。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。