如何为无__len__定义的对象添加__len__方法?实例绑定为何失效?
问题根源:特殊方法的查找规则
你遇到的问题核心在于Python对特殊方法(比如__len__)的查找机制:根据Python官方文档,特殊方法的隐式调用(比如len(obj)会触发obj.__len__())只会去对象的类层面查找,而不会检查实例自身的属性字典。
你的get_sections是function类的实例,当你给它单独赋值__len__ = lambda: calculated_length时,这个属性只存在于该函数实例的字典里,len()调用时会直接去function类里找__len__——而function类本身并没有实现这个方法,所以会抛出TypeError。
解决方案:包装生成器为带长度的可迭代对象
既然不能直接给生成器函数实例打补丁,我们可以把生成器包装在一个自定义类中,让这个类同时实现__iter__(保持生成器的懒加载特性)和__len__(提供长度信息)。
步骤1:先高效计算目标长度
首先,我们可以不用遍历生成器来计算长度(避免提前消耗生成器),直接从loaded_config_file里推导:
# 计算总section数量:遍历每个配置文件的sections长度求和 calculated_length = sum(len(config_parser.sections()) for config_parser in loaded_config_file.values())
步骤2:实现包装类
写一个简单的包装类,把生成器和长度绑定在一起:
class IterableWithLen: def __init__(self, iterable, length): self.iterable = iterable self._length = length def __iter__(self): # 返回原生成器,保持懒加载 return iter(self.iterable) def __len__(self): return self._length
步骤3:使用包装后的对象
把get_sections的生成器实例包装后,再传给sequence_timer:
# 创建生成器 sections_generator = get_sections(loaded_config_file) # 包装成带长度的可迭代对象 sections_with_len = IterableWithLen(sections_generator, calculated_length) # 传入sequence_timer for elem, progress_info in sequence_timer(sections_with_len, info_frequency=1): # 你的业务逻辑处理 section, module_file, config_parser = elem if progress_info: print(f"进度:{progress_info.progress*100:.2f}%,耗时:{progress_info.elapsed:.2f}s")
备选方案:转为列表(适合小数据量)
如果你的loaded_config_file数据量不大,也可以直接把生成器转为列表,列表天生支持len():
sections_list = list(get_sections(loaded_config_file)) for elem, progress_info in sequence_timer(sections_list, info_frequency=1): # 处理逻辑
这种方式简单,但会把所有元素加载到内存中,数据量大时不推荐。
内容的提问来源于stack exchange,提问作者Evandro Coan
相关产品推荐
相关产品推荐

