为什么重写 __iter__ 会抛出 RecursionError?

Why does overriding __iter__ throws RecursionError?

我想覆盖在外部库中定义的 ExternalIter__iter__ 方法,因此我无法更改 ExternalIter class 的源代码。我在 MyIter2MyIter3.

中实现了两种不同的覆盖方式
class ExternalIter:
    
    def __init__(self):
        self.x = iter([
            (1, 2),
            (3, 4),
            (5, 6),
            (7, 8),
            (9, 10)
        ])
        
    def __iter__(self):
        return self
        
    def __next__(self):
        return next(self.x)
    
class MyIter2(ExternalIter):
    
    def __iter__(self):
        while True:
            try:
                i, j = super().__next__()
                yield i
                yield j
            except StopIteration:
                break
    
class MyIter3(ExternalIter):
    
    def __iter__(self):
        for i, j in super().__iter__():
            yield i
            yield j

ExternalIter 的原始行为如下:

for i in ExternalIter():
    print(i)
# (1, 2)
# (3, 4)
# (5, 6)
# (7, 8)
# (9, 10)

我想覆盖 __iter__ 的行为,如下例所示:

for i in MyIter2():
    print(i)
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
# 10

MyIter2 正常工作。然而,另一种替代方法就像我在 MyIter3 中所做的那样抛出 RecursionError.

for i in MyIter3():
    print(i)
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
<ipython-input-8-4e1114201cac> in <module>
----> 1 for i in MyIter3():
      2     print(i)

<ipython-input-5-82da3324a8a3> in __iter__(self)
     30 
     31     def __iter__(self):
---> 32         for i, j in super().__iter__():
     33             yield i
     34             yield j

... last 1 frames repeated, from the frame below ...

<ipython-input-5-82da3324a8a3> in __iter__(self)
     30 
     31     def __iter__(self):
---> 32         for i, j in super().__iter__():
     33             yield i
     34             yield j

RecursionError: maximum recursion depth exceeded while calling a Python object

您能解释一下为什么第二种覆盖方法会抛出错误而第一种方法有效吗?如何在不获取 RecursionError 的情况下使用 super().__iter__() 覆盖 __iter__

您能否解释一下 __iter__ 在这种继承上下文中的工作原理,以了解为什么 super().__iter__() 指的是 self 而不是父项?

super().__iter__() returns self 之前 for 循环会隐式调用 iter(self),这将启动无限递归。

由于 for 循环的工作原理,我在这里看不到任何使用方法。您可以使用显式 while 循环来避免调用 __iter__.

def __iter__(self):

    while True:
        try:
            i, j = next(self)
        except StopIteration:
            break
        yield i
        yield j

这不会将 self 视为可迭代对象,仅将其视为迭代器。