Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么在这种特殊情况下使用生成器对象?_Python_List_Web Crawler_Generator - Fatal编程技术网

Python 为什么在这种特殊情况下使用生成器对象?

Python 为什么在这种特殊情况下使用生成器对象?,python,list,web-crawler,generator,Python,List,Web Crawler,Generator,我在看一段从网上下载的代码。这是为一个基本的网络爬虫。我遇到了以下for循环: for link in (links.pop(0) for _ in xrange(len(links))): ... 现在,我觉得以下代码也可以工作: for link in links: .... links=[] 通过研究,我发现第一个实例清除了链接,还生成了一个生成器对象(genexpr)链接从未在for循环中使用,因此其长度的减少与代码无关 使用xrange并每次弹出元素有什么特别的原因

我在看一段从网上下载的代码。这是为一个基本的网络爬虫。我遇到了以下
for
循环:

for link in (links.pop(0) for _ in xrange(len(links))):
    ...
现在,我觉得以下代码也可以工作:

for link in links:
    ....
links=[]
通过研究,我发现第一个实例清除了
链接
,还生成了一个
生成器对象(genexpr)
<代码>链接从未在
for
循环中使用,因此其长度的减少与代码无关


使用xrange并每次弹出元素有什么特别的原因吗?也就是说,使用generator对象是否比调用标准列表中的元素更有优势?此外,在什么情况下发电机是有用的;为什么?

很难为您引用的代码找到任何理由

我能想到的唯一一件事是
链接中的对象可能很大,或者与稀缺资源相关,因此尽快释放它们(而不是等到循环结束后才释放它们)可能很重要。但是(a)如果是这样,最好在创建每个链接时对其进行处理(可能使用生成器来组织代码),而不是在开始处理之前构建整个链接列表;(b)即使您别无选择,只能在处理之前构建整个列表,清除每个列表条目也比弹出列表便宜:

for i, link in enumerate(links):
    links[i] = None
    ...
(从包含n个项目的列表中弹出第一个元素需要O(n),尽管在实践中它会相当快,因为它是使用
memmove
实现的)

即使您绝对坚持在迭代时反复弹出列表,也最好这样编写循环:

while links:
    link = links.pop(0)
    ...

生成器的目的是避免生成大量的中间对象集合,这些中间对象不会为任何外部用途服务

如果所有代码都是在页面上构建链接集,那么第二个代码段就可以了。但可能需要的是一组根网站名称(例如google.com而不是google.com/q=some_search_term…)。如果是这样的话,那么你应该先查看链接列表,然后浏览完整的列表,去掉第一部分


这是第二个剥离部分,你可以通过使用发电机获得更多。你现在可以一个接一个地浏览每个链接,获得网站名称,而不需要一个包含所有链接的大中间列表。

也许
for
循环(在你的问题中省略)中的代码取决于
len(链接)这一事实
每次迭代都会减少?@FrédéricHamidi len(links)只会被调用once@robert,我指的是循环中的代码,我们看不到,而不是调用
xrange()
@FrédéricHamidi ah抱歉,你是对的。正如我提到的,
链接
从未在循环中使用。甚至它的长度都没有。它更短,更清晰,因为操作更少,并且避免了构造不必要的
xrange
和生成器对象。但是每个人都有自己的喜好,所以使用生成器版本不会错。在类似的情况下,我甚至使用了一个
ListPart
案例,它支持迭代和索引,以从列表中删除部分。如果评论允许换行符,我会把它放在这里(所以不可能这样做可能是好事);它可以像
a=ListPart([1,2,3,4])那样使用;b=a[2:4];c=清单(a);打印a、b、c
并打印myiter.ListPart([])[3、4][1、2]
。但即使在第二种情况下,假设我们正在剥离链接,我们最终一次只处理一个链接。
for
循环中的所有操作都处理
链接
,而不是
链接
。Python不会生成新的列表,无论
link
更改了多少。@shashwat是的,但是您创建的中间对象越少,性能就越好。速度也将通过生成生成器并在最后一刻调用生成器上的list()返回。一个列表中的很多附件会比较慢。@shashwat我不认为这样使用xrange(len(…)有什么意义