如何在__init__中重载__next__方法?动态替换失效问题解析
自定义Range生成器中__next__方法动态重载的问题
问题背景
我正在编写自定义range生成器类,希望根据参数step的正负,让__next__方法分别使用<=或>=比较起始值与终止值。想仅判断一次step的正负,再据此定义__next__方法,编写了如下代码(简化后仅支持三个参数输入):
class MyRange: def __init__(self, *args): self.min, self.max, self.step = args[0] - args[2], args[1], args[2] if self.step > 0: self.__next__ = self.next_pos else: self.__next__ = self.next_neg def __iter__(self): return self def __next__(self): pass def next_pos(self): self.min += self.step if self.min >= self.max: raise StopIteration return self.min def next_neg(self): self.min += self.step if self.min <= self.max: raise StopIteration return self.min
遇到的问题:
- 若不在类定义中显式写
__next__方法,会触发错误:TypeError: iter() returned non-iterator of type 'MyRange' - 原本以为会先通过类定义的
__next__初始化,再在__init__中覆盖,但实际未生效,想知道该方案失效的原因,以及如何在实例化时根据step重载__next__方法。 - 已知可以将
next_pos或next_neg存入self.my_comparison再在__next__中调用,但想了解在__init__中直接重载__next__的可行方式及当前问题的原因。
方案失效的原因
- 迭代器类型判定规则:Python判断一个对象是否为迭代器,是检查类是否定义了
__next__方法,而非实例是否拥有该属性。如果类中没有显式定义__next__,哪怕实例在__init__中绑定了该属性,Python依然会判定这个类不属于迭代器类型,从而抛出TypeError。 - 特殊方法的查找优先级:Python对双下划线特殊方法(如
__next__)的查找默认优先从类的方法字典中获取,而非直接读取实例属性。你在__init__中给实例绑定__next__的操作本身是生效的,但调用next()时,Python会忽略实例上的绑定,直接使用类层面定义的空__next__方法,所以看起来像是覆盖未生效。
在__init__中直接重载__next__的可行方式
方式1:通过__getattribute__拦截特殊方法查找
重写实例的__getattribute__方法,让Python查找__next__时优先返回实例绑定的实现,这种方式仅影响当前实例,不会干扰其他实例:
class MyRange: def __init__(self, *args): self.min, self.max, self.step = args[0] - args[2], args[1], args[2] # 把对应逻辑绑定到实例的私有属性 if self.step > 0: self._next_impl = self.next_pos else: self._next_impl = self.next_neg def __iter__(self): return self def __getattribute__(self, name): # 当查找__next__时,返回实例绑定的实现 if name == '__next__': return object.__getattribute__(self, '_next_impl') return object.__getattribute__(self, name) def next_pos(self): self.min += self.step if self.min >= self.max: raise StopIteration return self.min def next_neg(self): self.min += self.step if self.min <= self.max: raise StopIteration return self.min
方式2:动态修改类的__next__方法(不推荐)
如果你的类不会被多实例同时使用,可以直接在__init__中修改类的__next__方法,但这种方式会影响所有后续创建的MyRange实例:
class MyRange: def __init__(self, *args): self.min, self.max, self.step = args[0] - args[2], args[1], args[2] # 修改类层面的__next__方法 if self.step > 0: MyRange.__next__ = self.next_pos else: MyRange.__next__ = self.next_neg def __iter__(self): return self def __next__(self): pass def next_pos(self): self.min += self.step if self.min >= self.max: raise StopIteration return self.min def next_neg(self): self.min += self.step if self.min <= self.max: raise StopIteration return self.min
方式3:用闭包生成__next__逻辑
在__init__中直接定义闭包函数封装对应逻辑,再让类的__next__方法转发调用,这种方式简洁且仅影响当前实例:
class MyRange: def __init__(self, *args): self.min, self.max, self.step = args[0] - args[2], args[1], args[2] # 根据step生成对应的闭包函数 if self.step > 0: def _next(): self.min += self.step if self.min >= self.max: raise StopIteration return self.min else: def _next(): self.min += self.step if self.min <= self.max: raise StopIteration return self.min self._next = _next def __iter__(self): return self def __next__(self): return self._next()
内容的提问来源于stack exchange,提问作者user1095509
相关产品推荐
相关产品推荐

