自定义MERFISH_tools类中__next__魔法方法未调用原因排查
问题
尝试通过定义__iter__和__next__方法让自定义类MERFISH_tools可迭代,需求是:
- 当存在指定数据子集索引的
fov_list时,用yield语句迭代对应值; - 当
fov_list为空时,让__iter__返回类实例,通过调用__next__遍历全部数据直到触发StopIteration异常。
目前已经用其他方法解决问题,但疑惑:为什么fov_list为空时__next__方法没被调用?是不是yield语句影响了__next__的功能?
相关代码如下:
class MERFISH_tools(): def __init__(self): self.fov_list = [] FOV_list_path = os.path.join(os.path.dirname(os.path.dirname(config.get("merlin_folder"))),"analysis_parameters","fov_list","fov_list.txt") if os.path.exists(FOV_list_path): with open(FOV_list_path) as f: self.fov_list = [int(fov.strip() for fov in f.readlines()] # 原代码存在语法错误 def __iter__(self): if len(self.fov_list) == 0: self.i = 0 return self else: for fov in self.fov_list: yield fov,self[fov] def __next__(self) -> tuple: i = self.i self.i +=1 if self.i > self.positions.positions.shape[0]: raise StopIteration return i,self[i]
分析与解答
问题根源:语法错误+迭代器分支逻辑的触发问题
你遇到__next__未被调用的情况,核心是两个点:
原代码的语法错误
原代码中int(fov.strip() for fov in ...)少了一个闭合括号,正确写法是int(fov.strip())。这个错误会导致初始化阶段直接抛出异常,fov_list无法被正确赋值为空列表,自然走不到__iter__返回自身的分支,__next__也就没机会被调用。迭代器协议的分支独立性
就算修复了语法错误,你要明确:__iter__在fov_list非空时返回的是生成器对象(因为用了yield),生成器自带__next__逻辑,和类定义的__next__无关;而空列表时返回类实例,才会触发你写的__next__方法。这两个分支是完全独立的,互不干扰。
关于yield是否影响__next__?
明确说:yield不会影响类的__next__功能。yield只是让__iter__返回一个生成器,生成器的迭代逻辑由yield语句完全控制;当__iter__返回类自身时,Python才会调用你定义的__next__方法——两者没有互相覆盖或干扰的关系。
修正后的可行代码示例
如果要保留原需求的两种迭代方式,修正语法和细节后的代码如下:
import os # 假设config和positions已正确定义 class MERFISH_tools(): def __init__(self): self.fov_list = [] FOV_list_path = os.path.join( os.path.dirname(os.path.dirname(config.get("merlin_folder"))), "analysis_parameters", "fov_list", "fov_list.txt" ) if os.path.exists(FOV_list_path): with open(FOV_list_path) as f: # 修复语法错误:补充int()的闭合括号 self.fov_list = [int(fov.strip()) for fov in f.readlines()] # 确保self.positions已正确初始化 self.positions = ... def __iter__(self): if self.fov_list: # 更简洁的非空判断方式 for fov in self.fov_list: yield fov, self[fov] else: self.i = 0 return self def __next__(self) -> tuple: current_i = self.i self.i += 1 # 修正判断条件:避免索引越界(索引从0开始,用>=判断更合理) if current_i >= self.positions.positions.shape[0]: raise StopIteration return current_i, self[current_i] # 必须实现__getitem__方法,否则self[fov]会触发异常 def __getitem__(self, idx): # 这里编写根据索引获取对应数据的逻辑 return ...
内容的提问来源于stack exchange,提问作者Bereket Berackey
相关产品推荐
相关产品推荐

