使用生成器懒加载列表并持久化完整列表的实现疑问
解决方案
你遇到的核心问题是生成器属性无法直接返回列表,且原代码存在重复加载、迭代后无法直接获取完整列表的问题。以下是修正后的代码,完全满足你的需求:
import requests class Phone: def __init__(self, id, name, type): self.id = id self.name = name self.type = type def __str__(self): return self.name class A: def __init__(self): self._phones_cucm = [] self._phone_map = {} # 存储已加载的设备,避免重复请求 self._all_loaded = False # 标记是否已加载全部设备 def _gen_phones(self): for phone_id in self._phones_cucm: if phone_id not in self._phone_map: # 仅当未加载时才发起请求 resp = requests.get(f"https://example.com/phone/{phone_id}").json() self._phone_map[phone_id] = Phone(resp["id"], resp["name"], resp["type"]) yield self._phone_map[phone_id] # 迭代完成后标记所有设备已加载 self._all_loaded = True def get_phones(self, filter_type): self._phones_cucm = requests.get( f"https://example.com/phones?type={filter_type}" ).json() # 重置加载状态,避免旧数据干扰 self._phone_map.clear() self._all_loaded = False @property def phones(self): if self._all_loaded: # 已加载全部数据,直接返回完整列表 return list(self._phone_map.values()) # 未加载完成时返回生成器,支持懒加载迭代 return self._gen_phones() def main(): obj = A() obj.get_phones("desk_phone") # 迭代时懒加载每个设备的数据 for phone in obj.phones: print(phone) # 迭代完成后,直接获取完整列表 print(obj.phones) # 输出所有Phone对象的列表 if __name__ == "__main__": main()
关键修改说明
- 避免重复加载:用
_phone_map字典存储已加载的Phone对象,以设备ID为键,确保同一个设备不会重复发起请求。 - 加载状态标记:新增
_all_loaded标志位,当生成器迭代完成(所有设备加载完毕)时标记为True。 - 动态返回类型:
phones属性根据加载状态动态返回:- 未加载完成时返回生成器,实现迭代时逐个懒加载;
- 加载完成后直接返回完整的设备列表,满足你迭代后直接调用完整列表的需求。
- 重置状态:调用
get_phones时清空旧数据并重置加载状态,确保新的筛选条件能正确加载新数据。
原代码问题分析
- 生成器属性的误区:原代码中
phones属性用yield from返回生成器,导致每次访问obj.phones都会创建新的生成器对象,而非列表,这就是最后打印生成器而非列表的原因。 - 生成器return的无效性:生成器中的
return self._phones无法直接返回值,生成器的return值只会被封装在StopIteration异常的value属性中,无法通过常规迭代获取。 - 重复添加数据:原代码每次迭代生成器都会将Phone对象追加到
_phones列表,多次迭代会导致列表中出现重复对象。
内容的提问来源于stack exchange,提问作者Xemrer
相关产品推荐
相关产品推荐

