【问题标题】:Why use iter() to make a list an iterable?为什么使用 iter() 使列表成为可迭代的?
【发布时间】:2016-08-07 17:38:54
【问题描述】:
class Node:
    def __init__(self, value):
         self._value = value
         self._children = []
    def __repr__(self):
         return 'Node({!r})'.format(self._value)
    def add_child(self, node):
         self._children.append(node)
    def __iter__(self):
         return iter(self._children)
    def depth_first(self):
         yield self
         for c in self:
             yield from c.depth_first()
if __name__ == '__main__':
    root = Node(0)
    child1 = Node(1)
    child2 = Node(2)
    root.add_child(child1)
    root.add_child(child2)
    child1.add_child(Node(3))
    child1.add_child(Node(4))
    child2.add_child(Node(5))

for a in root.depth_first():
    print(a)
# Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)

我认为列表是一个我们可以对其进行迭代的对象,那么为什么要使用 iter() 呢?我是 python 新手,所以这看起来很奇怪。

【问题讨论】:

  • iter 不会使列表可迭代,它会返回一个迭代器。

标签: python list python-3.x iterator


【解决方案1】:

因为返回self._children 会返回一个list 对象,它不能用作迭代器,请记住,迭代器实现__next__ 方法以便在迭代期间提供项目:

>>> next(list())  # doesn't implement a __next__ method
TypeError: 'list' object is not an iterator

lists 是 iterable,它们可以被迭代,因为在其上调用 iter 将返回一个 iterator,但是,lists 本身不是迭代器——可以在this Question 的最佳答案中找到这些迭代器的详细分类。

每次调用__iter__ 时,列表__iter__ 方法都会返回一个自定义的新list_iterator 对象:

list().__iter__()
Out[93]: <list_iterator at 0x7efe7802d748>

并且,通过这样做,支持多次迭代,list_iterator 对象实现了所需的__next__ 方法。 调用并返回 iter 就可以了,返回列表迭代器并省去你必须实现 __next__ 的麻烦。


解决您关于for c in self._children 为何有效的评论,因为它本质上是在做同样的事情。 for 循环的基本情况是:

it = iter(self._children)  # returns the list iterator
while True:
    try:
        i = next(it)
        <loop body>
    except StopIteration:
        break

意思是,iter 在列表对象上再次被调用,并被for 循环用于next 调用。

【讨论】:

  • 我不明白返回列表对象是什么意思?当我尝试这段代码时,它运行良好class Node: def __init__(self, value): self._value = value self._children = [] def __repr__(self): return 'Node({!r})'.format(self._value) def add_child(self, node): self._children.append(node) def __iter__(self): return iter(self._children) def depth_first(self): yield self for c in self._children: yield from c.depth_first()
  • 为什么当我用(for c in self._children)改变(for c in self:) 时效果很好
【解决方案2】:

每个可迭代对象都实现了一个返回自身的iter() 函数。 iter(obj) 调用 obj.iter(),这与在您的示例中返回列表对象相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-04
    • 1970-01-01
    • 2021-01-20
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    相关资源
    最近更新 更多