为什么在自定义迭代器上隐式调用__len __()

时间:2014-08-13 16:36:21

标签: 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

    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)

此代码在没有__len__方法的情况下运行良好。删除这三行并运行上面的代码输出:

  first
  second
  third

但是,如果存在__len__方法,则结果为:

    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

请注意输出中是否存在firstprint_list()执行一次,但在递归之前隐式调用__len__()方法。什么叫这种方法?

我在python 3.3.1和2.7.3

中看到了相同的行为

1 个答案:

答案 0 :(得分:11)

您在布尔上下文中使用here

while here:

这将使用__len__查看它是否为空容器(例如是假y),请参阅Truth Value Testing

  

可以测试任何对象的真值,以便在ifwhile条件下使用,或者作为下面布尔运算的操作数。以下值被视为false:

     

[...]

     
      
  • 用户定义的类的实例,如果类定义了__nonzero__()__len__()方法,则该方法返回整数零或bool值False
  •   

对于您的用例,请改用is not None

while here is not None: