我正在查看从互联网上下载的一些代码。这是一个基本的webcrawler。我遇到了以下for
循环:
for link in (links.pop(0) for _ in xrange(len(links))):
...
现在,我觉得以下代码也可以使用:
for link in links:
....
links=[]
研究,我发现第一个实例清除links
并生成generator object (genexpr)
。 links
循环中从不使用for
,因此其长度的减少与代码无关。
使用xrange是否有任何特殊原因,每次弹出元素?即使用生成器对象而不是调用标准列表的元素是否有任何优势?此外,在什么情况下发电机是有用的;为什么呢?
答案 0 :(得分:6)
很难看出你引用的代码有任何理由。
我唯一能想到的是links
中的对象可能很大,或者与稀缺资源相关联,因此尽快释放它们可能很重要(而不是等到循环结束以释放它们全部)。但是(a)如果是这样,最好在创建它时处理每个链接(可能使用生成器来组织代码),而不是在开始处理它之前构建整个链接列表; (b)即使您在处理之前别无选择,只能建立整个列表,清除每个列表条目比弹出列表要便宜:
for i, link in enumerate(links):
links[i] = None
...
(使用 n 项从列表中弹出第一个元素需要O( n ),尽管在实践中它会相当快,因为它是使用{{1}实现的}。)
即使您在迭代时反复弹出列表,也绝对坚持,最好像这样编写循环:
memmove
答案 1 :(得分:0)
生成器的目的是避免构建大量的中间对象集合,这些对象不会用于任何外部用途。
如果所有代码都在构建页面上的链接集,那么第二个代码片段就可以了。但也许可能需要的是一组根网站名称(例如google.com而不是google.com/q=some_search_term ....)。如果是这种情况,那么您将获取链接列表,然后浏览完整列表,仅删除第一部分。
这是第二次剥离部分,你可以通过使用发电机获得更多。您现在可以逐个浏览每个链接,获取网站名称而不需要包含所有链接的大型中间列表,而不是不必要地构建一个需要内存和时间来构建的链接列表。