Python 为什么在自定义迭代器上隐式调用_len__;()

Python 为什么在自定义迭代器上隐式调用_len__;(),python,Python,我正在编写一个简单的链表实现,如下所示: class Node(object): def __init__(self, value): self.value = value self._next = None def __iter__(self): here = self while here: yield here here = here._next de

我正在编写一个简单的链表实现,如下所示:

class Node(object):
    def __init__(self, value):
        self.value = value
        self._next = None

    def __iter__(self):
        here = self
        while here:
            yield here
            here = here._next

    def __len__(self):
        print("Calling __len__ on: {}".format(self))
        return sum(1 for _ in self)

    def append_to_tail(self, value):
        if self._next is None:
            self._next = Node(value)
        else:
            self._next.append_to_tail(value)

def print_list(ll):
    print(ll.value)
    if ll._next:
        print_list(ll._next)

my_list = Node('a')
my_list.append_to_tail('b')
my_list.append_to_tail('c')

print_list(my_list)
此代码在没有
\uuu len\uuu
方法的情况下运行良好。删除这三行并运行上述代码输出:

  first
  second
  third
但是,如果存在
\uuuu len\uuu
方法,则结果为:

    first
    Calling __len__ on: <__main__.Node object at 0x108804dd0>
    Calling __len__ on: <__main__.Node object at 0x108804dd0>
    <snip>
    Calling __len__ on: <__main__.Node object at 0x108804dd0>
    Calling __len__ on: <__main__.Node object at 0x108804dd0>
    Traceback (most recent call last):
      File "len_example.py", line 31, in <module>
        print_list(my_list)
      File "len_example.py", line 24, in print_list
        if ll._next:
      File "len_example.py", line 14, in __len__
        return sum(1 for _ in self)
      File "len_example.py", line 14, in <genexpr>
        return sum(1 for _ in self)
      File "len_example.py", line 8, in __iter__
        while here:
      File "len_example.py", line 14, in __len__
        return sum(1 for _ in self)
      File "len_example.py", line 14, in <genexpr>
        return sum(1 for _ in self)
    <snip>
      File "len_example.py", line 8, in __iter__
        while here:
      File "len_example.py", line 13, in __len__
        print("Calling __len__ on: {}".format(self))
    RuntimeError: maximum recursion depth exceeded while calling a Python object
首先
在以下位置调用“len”:
在以下位置调用“len”:
在以下位置调用“len”:
在以下位置调用“len”:
回溯(最近一次呼叫最后一次):
文件“len_example.py”,第31行,在
打印列表(我的列表)
打印列表中第24行的文件“len_example.py”
如果是,下一步:
文件“len_example.py”,第14行,in__len__
返回和(1表示uu自身)
文件“len_example.py”,第14行,在
返回和(1表示uu自身)
iter中第8行的文件“len_example.py”__
在这里:
文件“len_example.py”,第14行,in__len__
返回和(1表示uu自身)
文件“len_example.py”,第14行,在
返回和(1表示uu自身)
iter中第8行的文件“len_example.py”__
在这里:
文件“len_example.py”,第13行,in__len__
打印(“调用{}.format(self))
RuntimeError:调用Python对象时超出了最大递归深度
注意输出中是否存在
第一个
print\u list()
执行一次,但在递归之前,有东西隐式调用了
\uu len\uuu()
方法。这个方法叫什么


我看到python 3.3.1和2.7.3的行为与您在布尔上下文中使用的
相同:

while here:
这将使用
\uuuu len\uuuu
查看它是否为空容器(例如为false-y),请参阅:

任何对象都可以测试真值,用于
if
while
条件,或作为下面布尔运算的操作数。以下值被认为是错误的:

[……]

  • 用户定义类的实例,如果该类定义了一个
    \uuuu非零\uuuuuuuuuu()
    \uuuuuuu len\uuuuuuuuu()
    方法,则该方法返回整数零或布尔值
    False
对于您的用例,请使用
而不是None

while here is not None: