在我的网络爬虫中,我有一个类跟踪要抓取的网址,删除重复项等:
class VisitOnlyOnceClerk(object):
def __init__(self):
self.visited = set()
self.to_visit = set()
def enqueue(self, url, referer):
if not url in self.visited:
self.to_visit.add((url, referer))
def __bool__(self):
return bool(self.to_visit)
def __iter__(self):
while self.to_visit:
(url, referer) = self.to_visit.pop()
self.visited.add(url)
yield (url, referer)
这提供了一个可以添加值的迭代:
clerk = VisitOnlyOnceClerk()
clerk.enqueue(starting_point, starting_point)
for (url, referer) in clerk:
# get the url, and clerk.enqueue() all the links from it ...
这似乎是一个可以由协程执行的任务。我已经看到了仅仅产生值的协同程序的例子,以及仅消耗价值的例子,但是没有两个同时消耗价值的例子。类似的东西:
def visit_once_clerk():
visited = set()
to_visit = set([(yield)])
for i in to_visit:
visited.add(i[1])
extras = (yield i)
if extras:
to_visit.union(i for i in extras if i[1] not in visited)
当然,这并不像我认为的那样有效。协同程序甚至是正确的工具吗?在这种情况下使用它们的正确方法是什么?
答案 0 :(得分:0)
我不认为协程是你的类生成器的方法恕我直言的方式是比Python协程允许你做的方式更易读,易懂和易于使用。
在此我要说明的是我将如何实现协程:
def visit_once_clerk(start_point=None):
visited = set()
to_visit = set(start_point or [])
while to_visit:
value = (yield to_visit.pop())
if value and value not in visited:
to_visit.add(value)
这是应该如何使用的:
clerk = visit_once_clerk(['start'])
print clerk.next() # Print: start
print clerk.send('test') # Print: test
print clerk.next() # Raise StopIteration
注意:您可以看到两个实施之间存在差异,特别是send
和enqueue
操作,send
操作会立即生成值 ITOH < / strong> enqueue
会安排新值为任意产生(因为使用了set
)