2016-05-27 5 views
2

で同じ発電機の繰り返し次の簡単なジェネレータ考えてみましょう:チェーンのpython

def simple_gen(): 
    for number in range(5): 
     yield number ** 2 

を私はチェーンにユーザーitertools.repeatitertools.chainに喜んn回発生装置自体に。明確にするために同じの次(非発電機)の例を検討:

array = [1,2,3,4] 
repetitions = itertools.repeat(array ,2) 
list(itertools.chain.from_iterable(repetitions)) -> [1,2,3,4,1,2,3,4] 

を私が同じことをしたいが、配列の代わりに自分の発電機(simple_gen)を使用します。もちろん、itertools.repeatが同じオブジェクトを繰り返すため、単純な置換が機能しないため、ジェネレータの次の繰り返しが使い果たされます。

itertoolsモジュールを使用してこれを達成する方法のいくつかのアイデアはありますか?

ジェネレータをリストまたは別のコンテナにキャストしたくありません。

+0

ジェネレータの長さをご存知ですか?もしそうなら、 'itertools.cycle'を使うことができます。 –

+0

いいえ、私は発電機の長さを知らない。 – Dargor

答えて

4

あなたは最初のリストに発電機の出力を変換することができます:

repeat(list(simple_gen()), 2) 

あなたはは、そうでない場合は、発電機出力を繰り返すことはできません。代わりのchain.from_iterable(repeat(callable(), count))のPython 2との使用のため

from itertools import repeat 

def recreate(callable, count=None): 
    for c in repeat(callable, count): 
     yield from c() 
のPython 3で

from itertools import repeat 

def recreate(callable, count=None): 
    for c in repeat(callable, count): 
     for val in c(): 
      yield val 

:せいぜいあなたは 回の発電 番号を再作成することができます。ジェネレータ関数はと呼ばれていない であることに注意してください。代わりに関数オブジェクト自体を渡してください。

デモ:

>>> from itertools import repeat 
>>> def simple_gen(): 
...  for number in range(5): 
...   yield number ** 2 
... 
>>> def recreate(callable, count=None): 
...  for c in repeat(callable, count): 
...   for val in c(): 
...    yield val 
... 
>>> list(recreate(simple_gen, 2)) 
[0, 1, 4, 9, 16, 0, 1, 4, 9, 16] 
+0

ジェネレータをリストにキャストしたくないので、RAM全体がいっぱいになってしまいます。だから私はジェネレータを使っている。私はそれで私の質問を更新します。 – Dargor

+0

@Dargor:私はあなたに別の選択肢を与えたのです。他の選択肢はありません、私は恐れています。 –

+0

はい、はい。それは私の質問が不完全であり、リストにキャスティングを使用して他の答えにつながる可能性があるという悪い答えではありません。これは素晴らしい答えです。誤解をおかけして申し訳ありません。 :) – Dargor

2

どうデコレータについて:

from itertools import repeat 

class repeat_gen: 
    def __init__(self, count): 
     self.count = count 

    def __call__(self, gen): 
     for it in repeat(gen, self.count): 
      yield from it() 

@repeat_gen(3) 
def simple_gen(): 
    for number in range(5): 
     yield number ** 2 

print(list(simple_gen)) 

注すぎitertools.repeat作品せずに、次のことを。 simple_genは汎用関数としてデコレータに渡されるため、複数回呼び出すことができます。

class repeat_gen: 
    def __init__(self, count): 
     self.count = count 

    def __call__(self, gen): 
     self.gen = gen 
     def repeat_gen(): 
      for i in range(self.count): 
       yield from self.gen() 
     return repeat_gen 

@repeat_gen(3) 
def simple_gen(): 
    for number in range(5): 
     yield number ** 2 

print(list(simple_gen())) 
+0

このコードでは、Python 2.XとPython 3.Xの熟語が奇妙に混在しています。例えば、 'object'から継承する必要はなく、ループする代わりに' it(yield) 'から継承することができます。両方のバージョンでコードを動作させたい場合は、引数を 'super'呼び出しに追加することができます。私はデコレータの考えが好きです。 –

+0

私は決してそれから歩くことはなかった()。ありがとう!それは大好きです。私はPython3への移行中です。おそらくコードが奇妙に見えるのです。 'yield from it()'で使われていないPython2の機能は何ですか? –

+0

'object'から明示的に継承する必要はありません。つまり、' class repeat_gen: 'がより一般的な宣言になります。 –