我正在根据大文本文件的内容在屏幕分析的上下文中写一篇关于生成器的博客文章,或者向API发出大量请求,并且在阅读this nifty comic by Julia Evans之后,我想检查一下。
假设我在Linux或OS X上。
让我们说我用scrapy制作一个屏幕刮板(知道scq这个qn并不是那么重要,但它可能是有用的背景)
如果我有一个这样的打开文件,我就可以为每一行返回一个scrapy.Request
,我从一个大的csv文件中提取。
with open('top-50.csv') as csvfile:
urls = gen_urls(csvfile)
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
gen_urls是一个看起来像这样的函数。
def gen_urls(file_object):
while True:
# Read a line from the file, by seeking til you hit something like '\n'
line = file_object.readline()
# Drop out if there are no lines left to iterate through
if not line:
break
# turn '1,google.com\n' to just 'google.com'
domain = line.split(',')[1]
trimmed_domain = domain.rstrip()
yield "http://domain/api/{}".format(trimmed_domain)
这很有效,但我想了解幕后发生的事情。
当我将csvfile
传递给gen_urls()
时,如此:
urls = gen_urls(csvfile)
在gen_urls
我的理解是,它通过在file_object.readline()
的while循环中一次拉出一行,然后与yield "http://domain/api/{}".format(trimmed_domain)
屈服。
在幕后,我认为是对某些文件描述符的引用,而readline()
实际上是在文件中寻找转发,直到它找到下一个换行\n
字符,并且yield基本上暂停了这个直到下一次调用__.next__()
或内置next()
时才会运行,此时它会恢复循环。下一个在代码片段的循环中隐式调用,如下所示:
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
因为我们当时只从文件描述符中提取一行,然后暂停'带有收益的函数,我们不会在内存中加载大量的东西。因为scrapy使用了一个事件模型,所以你可以创建一堆scrapy.Request
个对象,而不会立即发送大量的HTTP请求并使网络饱和。通过这种方式,scrapy还可以执行一些有用的操作,例如限制它们发送的速度,同时发送的数量等等。
这是关于对吗?
我主要是寻找一个心智模型,帮助我考虑在python中使用生成器并向其他人解释,而不是所有血淋淋的细节,因为我已经多年来一直在使用它们,而没有考虑发生了什么,我想在这里要求可能会有所启发。