You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在__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__的可行方式及当前问题的原因。

方案失效的原因

  1. 迭代器类型判定规则:Python判断一个对象是否为迭代器,是检查类是否定义了__next__方法,而非实例是否拥有该属性。如果类中没有显式定义__next__,哪怕实例在__init__中绑定了该属性,Python依然会判定这个类不属于迭代器类型,从而抛出TypeError。
  2. 特殊方法的查找优先级: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 11:59:54