0

私は新しいPythonプログラマーですが、これまで理解してきたことですが、「yield」キーワードは、ジェネレーター関数がジェネレーターオブジェクトのみを返す代わりにオブジェクトを返します。

したがって、10Kのアイテムを含むリストがある場合、リストに値を追加せずにスマートでPythonのソリューションを作成して大きくする方法を教えてください。

つまり、リストにいくつかの値を追加すると、最後に次のような大きなリストが作成されます。

def example():
    final_list = []
    for i in range(0,10000):
        final_list.append(i)
    return final_list

これは単なる例であり、実際の問題ではありません。ループを生成するためだけにrange()を使用しました。実際の問題では、シーケンシャルデータはなく、ランダムな文字列になり、findlaリストには10​​Kの文字列が含まれます。したがって、効率的なpythonicの方法でリストに追加せずに、すべての値を取得するにはどうすればよいですか。

ありがとう。

4

7 に答える 7

5

あなたの例は単純化されすぎているので、代わりに10000個のランダムな数字が必要だとしましょう。

ジェネレータを作成する方法は2つあります。1つは次のyieldステートメントです。

def example():
    for i in xrange(10000):
        yield random.random()

もう1つの方法は、ジェネレータ式を使用することです。

(random.random() for i in xrange(10000))

どちらを選択するかは、コードの複雑さによって異なります。

于 2012-05-14T18:59:40.360 に答える
2

私があなたをよく理解しているなら、あなたrange(0, 10000)はシーケンスをシミュレートするためだけを使用します。yield関数定義でを使用するときはいつでも、それはジェネレーター関数になります。ジェネレーター関数が使用される(呼び出される)と、イテレーターが返されます。表示されません。gen()代わりに次を試してください。

def gen(n):
    while n > 0:
        yield n
        n -= 1    # decrement the value

次に、通常はループで使用します。

for x in gen(10000):
    print x,         # comma to suppress new line

yield sリストを作成する代わりに、文字列を返す関数がある場合。次に、ジェネレーター関数を呼び出して、必要な値のみを収集します(ここでは、文字列ではなく、100で割り切れる数値)。

lst = []   # init
for x in gen(10000):
    if x % 100 == 0:
        lst.append(x)
print lst

ループは、いわゆるリスト内包に置き換えることもできます。

lst = [ x for x in gen(10000) if x % 100 == 0 ]
print lst

...次のように同じように書くと、より理解しやすくなります(つまり、上記のループに似ています)。

lst = [ x 
        for x in gen(10000) 
            if x % 100 == 0 ]
print lst

ただし、シーケンスが予想される場所であればどこでもジェネレーター関数を使用できます。ジェネレーターが要素を収集するかどうかの決定を実装できる場合は、次のように生成された要素のリストを作成できます。

lst = list(gen(100))
print lst
于 2012-05-14T18:58:17.857 に答える
2

あなたが言った:

Webページをクロールし、それらの文字列をリストに追加した後、文字列を取得しています。クローラーが大きなデータを取得すると、リストが大きくなり、最後にリストを繰り返したいときに、時間とメモリを消費します。

それで:

# generator function to crawl web pages
def crawler():
    while iStillHaveWebPagesToCrawl():
        someStrings = getSomeStringsFromAWebPage()
        for aString in someStrings:
            yield aString

def oneStringAtATime():
    for aString in crawler():
        doSomethingWith( aString )

を呼び出すと、 ;oneStringAtATime()と呼ばれるジェネレーター関数が設定されます。を実行するcrawler()たびに、のループはその文字列で1回繰り返されます。Webページが不足して関数を終了すると、ループが終了します。crawler()yieldoneStringAtATime()crawler()oneStringAtATime()

于 2012-05-14T21:50:20.003 に答える
0

わかりました。質問を読んだり、OPコードと以下のコメントを確認したりすると、OPがリストを処理しているように見えます。

それで、

def example():
    final_list = range(0, 10000) # or xrange() for v 2.x
    return final_list

おそらく一時的なfinal_list変数なしでも実行できますが、わかりやすくするために残しておきます。

リストの値がrange/xrangeによって生成された系列以外のものである場合、リスト内包はここで適切です。

それでも、質問は少し不明確だと感じています。

于 2012-05-14T18:40:13.667 に答える
0
>>> xrange_object = xrange(10000)
>>> xrange_object[0]
0
>>> xrange_object[1]
1

質問を編集したようです。ランダムな文字列生成関数がある場合はran_string、次のように、ジェネレータ式を使用して必要な処理を実行できます。

>>> final_gen = (ran_string(i) for i in xrange(10000))
于 2012-05-14T18:43:53.617 に答える
0

あなたはあなたの質問であまり明確ではありませんでした-あなたがここで探しているのはジェネレータ式です。

例えば:

>>> values = (random.random() for _ in range(10))
>>> for value in values:
...     print(value)
... 
0.32161489939829857
0.285715480204797
0.4961165128957876
0.42658612656828354
0.5083396364418685
0.00843781669361321
0.49698036590463757
0.8067300769956716
0.5741614069287628
0.4728079544997392

次に、持っている値を反復処理する場合は、ジェネレーター式を使用して、事前にリストを作成せずに、既存の反復可能オブジェクトに基づいて値を生成できます。それらは要求されたとおりに生成されます(この場合、ループがそれらを要求したとき)。

ジェネレータ式の構文の詳細な説明については、上記のリンク先のビデオを確認してください(そして、すべてのいとこ、リストコンプ、セットコンプなど)。

于 2012-05-14T18:45:26.223 に答える
0

あなたの質問は少し不明確ですが、あなたが意味するのは、反復できるオブジェクトが欲しいということだと思いますが、それは怠惰です-つまり、すべての値を事前に計算して保存するわけではありません。

def example():
    for i in xrange(10000):
        yield i

g = example()
print g.next() # prints '0'
print g.next() # prints '1'
for x in g:
    print x # prints '2', '3', ..., '10000'

例ではxrangeを使用しました。これは、rangeを使用すると目的が損なわれるため、関数に必要なものを何でも入れることができることは明らかです。それが機能する方法は、gがその内部状態(この場合はiの値)を記憶し、g.next()を呼び出すか、gを反復処理するたびに、次のyieldステートメントまで実行されることです。

お役に立てば幸いです。

于 2012-05-14T19:04:37.290 に答える