如何实现Python子类共享父类数据,避免重复调用下载方法?
解决子类实例共享父类数据避免重复下载的问题
你的场景很典型——多个子类实例化时重复触发父类的下载操作,既浪费资源又没必要。这里有几种简单靠谱的实现方式,能让所有子类共享同一份下载好的数据:
方法一:用类属性缓存下载结果
最直接的方式就是在父类里用一个类属性存储已下载的数据,每次调用get_data时先检查缓存是否存在,存在就直接返回,不存在再执行下载:
from time import time class data(object): # 类属性,所有实例共享的缓存容器 _cached_data = None def get_data(self): if self._cached_data is None: self._cached_data = self._download_data() return self._cached_data def _download_data(self): """ download data code """ print("data downloaded") return time() class A(data): def __init__(self): self.data = self.get_data() print(self.data) class B(data): def __init__(self): self.data = self.get_data() print(self.data) if __name__ == "__main__": a = A() b = B()
运行结果会变成:
data downloaded 1523989483.9526002 1523989483.9526002
只有第一次调用会触发下载,后续不管哪个子类的实例,都会直接复用缓存好的数据。
方法二:用装饰器实现懒加载缓存
如果不想修改父类核心结构,也可以用装饰器给_download_data方法加上缓存功能,让方法自动复用返回结果:
from time import time from functools import lru_cache class data(object): def get_data(self): return self._download_data() # 用lru_cache装饰,永久缓存方法返回值 @lru_cache(maxsize=None) def _download_data(self): """ download data code """ print("data downloaded") return time() # 子类部分保持不变 class A(data): def __init__(self): self.data = self.get_data() print(self.data) class B(data): def __init__(self): self.data = self.get_data() print(self.data) if __name__ == "__main__": a = A() b = B()
这里因为是实例方法,lru_cache会把实例本身作为缓存key,但由于_download_data不需要实例参数,所以能正常工作。如果担心这个,也可以把_download_data改成静态方法或类方法。
方法三:单例模式(适合数据全局唯一的场景)
如果你的data类本身只需要存在一份实例,那可以用单例模式,让所有子类共享同一个父类实例的数据:
from time import time class data(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls, *args, **kwargs) # 创建单例时一次性下载好数据 cls._instance._cached_data = cls._instance._download_data() return cls._instance def get_data(self): return self._cached_data def _download_data(self): print("data downloaded") return time() class A(data): def __init__(self): self.data = self.get_data() print(self.data) class B(data): def __init__(self): self.data = self.get_data() print(self.data) if __name__ == "__main__": a = A() b = B() print(a is b) # 输出True,说明是同一个实例
这种方式下,不管实例化多少次A或B,本质上都是用同一个父类实例,自然就共享同一份数据了。
总结
- 仅需缓存数据时,优先用方法一,简单直观,代码改动最小;
- 想灵活缓存方法结果时,用方法二的装饰器方案;
- 父类本身需要全局唯一时,用方法三的单例模式。
内容的提问来源于stack exchange,提问作者onon99buynoodle
相关产品推荐
相关产品推荐

