4

インターネットからダウンロードしたコードを少し見ていました。基本的なWebクローラー用です。for私は次のループに出くわしました:

for link in (links.pop(0) for _ in xrange(len(links))):
    ...

今、私は次のコードも機能すると思います:

for link in links:
    ....
links=[]

調べてみると、最初のインスタンスがクリアlinksされ、も生成されることがわかりましたgenerator object (genexpr)linksループで使用されることはないforため、長さが短くなることはコードとは関係ありません。

xrangeを使用し、毎回要素をポップする特別な理由はありますか?つまり、標準リストの要素を呼び出すよりもジェネレータオブジェクトを使用することに利点はありますか?さらに、どのような場合にジェネレータが役立つでしょうか。なぜ?

4

2 に答える 2

6

あなたが引用したコードの正当性を理解するのは難しいです。

私が考えることができる唯一のことは、のオブジェクトlinksが大きいか、そうでなければ不足しているリソースに関連付けられている可能性があるため、(ループの終わりまで待ってすべてを解放するのではなく)できるだけ早くそれらを解放することが重要かもしれないということです)。ただし、(a)その場合は、処理を開始する前にリンクのリスト全体を作成するのではなく、作成時に各リンクを処理する方が適切です(おそらく、ジェネレーターを使用してコードを整理します)。(b)処理する前にリスト全体を作成する以外に選択肢がなかったとしても、リストをポップするよりも、各リストエントリをクリアする方が安価です。

for i, link in enumerate(links):
    links[i] = None
    ...

(リストから最初の要素をn個のアイテムでポップすると、O(n)が必要になりますが、実際には、を使用して実装されているため、かなり高速になりますmemmove。)

リストを繰り返しポップすることを絶対に主張したとしても、次のようなループを作成することをお勧めします。

while links:
    link = links.pop(0)
    ...
于 2012-12-06T12:29:42.840 に答える
0

ジェネレータの目的は、外部での使用に役立たない中間オブジェクトの大規模なコレクションの構築を回避することです。

すべてのコードがページ上にリンクのセットを構築している場合は、2番目のコードスニペットで問題ありません。しかし、おそらく望ましいのは、ルートWebサイト名のセットです(たとえば、google.com / q = some_search_term ....ではなくgoogle.com)。この場合は、リンクのリストを取得してから、最初の部分だけを取り除いて完全なリストを調べます。

ジェネレーターを使用することでより多くを得ることができるのは、この2番目のストリッピング部分です。構築にメモリと時間がかかるリンクのリストを不必要に構築するのではなく、各リンクを1つずつ通過して、すべてのリンクの大きな中間リストなしでWebサイト名を取得できるようになりました。

于 2012-12-06T12:35:25.387 に答える